You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by wu...@apache.org on 2023/12/25 14:42:28 UTC
(skywalking-rover) branch main updated: Support collecting the access log from Kubernetes (#107)
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 c979bbf Support collecting the access log from Kubernetes (#107)
c979bbf is described below
commit c979bbf0271b37bfb68f531b2140afe55f634072
Author: mrproliu <74...@qq.com>
AuthorDate: Mon Dec 25 22:42:23 2023 +0800
Support collecting the access log from Kubernetes (#107)
---
CHANGES.md | 1 +
bpf/accesslog/accesslog.c | 59 ++
bpf/accesslog/common/connection.h | 322 +++++++++++
bpf/accesslog/common/data_args.h | 110 ++++
.../continuous/skb.h => accesslog/common/sock.h} | 40 +-
bpf/accesslog/l24/l24.h | 139 +++++
bpf/accesslog/l24/nf.c | 54 ++
.../register.go => bpf/accesslog/l24/read_l2.c | 34 +-
bpf/accesslog/l24/read_l3.c | 176 ++++++
bpf/accesslog/l24/read_l4.c | 59 ++
bpf/accesslog/l24/write_l2.c | 72 +++
bpf/accesslog/l24/write_l3.c | 147 +++++
bpf/accesslog/l24/write_l4.c | 103 ++++
.../network.go => bpf/accesslog/process/process.c | 67 +--
.../protocol.go => bpf/accesslog/process/process.h | 20 +-
bpf/accesslog/syscalls/close.c | 70 +++
bpf/accesslog/syscalls/connect.c | 149 +++++
bpf/accesslog/syscalls/connect_conntrack.c | 117 ++++
bpf/accesslog/syscalls/connect_conntrack.h | 99 ++++
bpf/accesslog/syscalls/transfer.c | 634 +++++++++++++++++++++
bpf/accesslog/syscalls/transfer.h | 352 ++++++++++++
bpf/accesslog/tls/go_tls.c | 195 +++++++
bpf/accesslog/tls/go_tls.h | 49 ++
bpf/accesslog/tls/node_tls.c | 50 ++
bpf/accesslog/tls/node_tls.h | 79 +++
bpf/accesslog/tls/openssl.c | 132 +++++
.../protocol.go => bpf/accesslog/tls/openssl.h | 8 -
.../enums/protocol.go => bpf/accesslog/tls/tls.h | 16 +-
bpf/include/list.h | 102 ++++
bpf/include/protocol_analyzer.h | 16 +
bpf/{profiling/network => include}/socket.h | 29 +-
bpf/include/socket_opts.h | 57 ++
bpf/include/socket_reader.h | 64 +++
bpf/profiling/continuous/network.c | 9 +-
bpf/profiling/continuous/network.h | 9 +-
bpf/profiling/network/args.h | 36 +-
configs/rover_configs.yaml | 18 +-
go.mod | 12 +-
go.sum | 28 +-
.../host/network.go => accesslog/bpf/loader.go} | 56 +-
pkg/accesslog/collector/close.go | 56 ++
.../skb.h => pkg/accesslog/collector/collector.go | 41 +-
pkg/accesslog/collector/connect.go | 162 ++++++
pkg/accesslog/collector/l24.go | 93 +++
.../register.go => accesslog/collector/process.go} | 41 +-
pkg/accesslog/collector/protocols/http1.go | 234 ++++++++
pkg/accesslog/collector/protocols/http2.go | 314 ++++++++++
pkg/accesslog/collector/protocols/protocol.go | 92 +++
pkg/accesslog/collector/protocols/queue.go | 282 +++++++++
pkg/accesslog/collector/tls.go | 87 +++
pkg/accesslog/collector/transfer.go | 77 +++
.../process.go => accesslog/common/accesslog.go} | 27 +-
.../base/process.go => accesslog/common/config.go} | 42 +-
pkg/accesslog/common/connection.go | 447 +++++++++++++++
pkg/accesslog/common/queue.go | 141 +++++
.../enums/protocol.go => accesslog/common/type.go} | 9 +-
.../enums/protocol.go => accesslog/events/base.go} | 17 +-
.../register.go => accesslog/events/close.go} | 37 +-
pkg/accesslog/events/connect.go | 59 ++
.../network/analyze => accesslog}/events/data.go | 73 +--
pkg/accesslog/events/detail.go | 73 +++
.../network.go => accesslog/forwarder/close.go} | 50 +-
pkg/accesslog/forwarder/connect.go | 64 +++
.../forwarder/forwarder.go} | 53 +-
.../enums => accesslog/forwarder}/protocol.go | 14 +-
pkg/accesslog/forwarder/transfer.go | 141 +++++
pkg/{process => accesslog}/module.go | 56 +-
pkg/accesslog/runner.go | 321 +++++++++++
pkg/boot/register.go | 2 +
pkg/process/api.go | 7 +
pkg/process/api/process.go | 22 +
pkg/process/finders/base/finder.go | 15 +-
pkg/process/finders/context.go | 11 +-
pkg/process/finders/kubernetes/finder.go | 104 ++--
pkg/process/finders/kubernetes/process.go | 8 +
pkg/process/finders/manager.go | 27 +-
pkg/process/finders/scanner/finder.go | 82 ++-
pkg/process/finders/scanner/process.go | 18 +-
pkg/process/finders/storage.go | 13 +-
pkg/process/module.go | 8 +
.../continuous/checker/bpf/network/reader.go | 10 +-
.../task/network/analyze/base/connection.go | 10 +-
pkg/profiling/task/network/analyze/base/context.go | 44 +-
pkg/profiling/task/network/analyze/base/metrics.go | 8 +-
.../task/network/analyze/base/tcpresolver.go | 155 -----
pkg/profiling/task/network/analyze/base/traffic.go | 38 +-
pkg/profiling/task/network/analyze/events/data.go | 66 +--
.../task/network/analyze/events/sockets.go | 8 +-
.../task/network/analyze/layer4/events.go | 8 +-
.../task/network/analyze/layer4/listener.go | 15 +-
.../task/network/analyze/layer7/listener.go | 3 +-
.../analyze/layer7/protocols/base/analyzer.go | 8 +-
.../analyze/layer7/protocols/base/protocol.go | 9 +-
.../analyze/layer7/protocols/http1/analyzer.go | 17 +-
.../analyze/layer7/protocols/http1/metrics.go | 21 +-
.../layer7/protocols/http1/reader/reader.go | 8 +-
.../layer7/protocols/http1/reader/request.go | 6 +-
.../layer7/protocols/http1/reader/response.go | 4 +-
.../analyze/layer7/protocols/http1/sampling.go | 2 +-
.../network/analyze/layer7/protocols/protocols.go | 11 +-
pkg/tools/btf/linker.go | 3 +
.../network/analyze => tools}/buffer/buffer.go | 228 ++++++--
.../analyze => tools}/buffer/buffer_test.go | 0
.../network/analyze => tools}/enums/protocol.go | 0
.../events/enums.go => tools/enums/socket.go} | 34 +-
pkg/tools/host/network.go | 8 +-
pkg/tools/ip.go | 6 -
.../analyze/enums/protocol.go => tools/ip/bpf.go} | 18 +-
pkg/tools/ip/tcpresolver.go | 60 ++
pkg/tools/ssl/gotls.go | 18 +-
.../protocols/base => tools/tracing}/tracing.go | 31 +-
111 files changed, 7109 insertions(+), 957 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 9ea818f..cc9b323 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Release Notes.
* Add `HasOwnerName` to judgement pod has owner name.
* Publish the `latest` Docker image tag.
* Improve the stability of Off CPU Profiling.
+* Support collecting the access log from Kubernetes.
#### Bug Fixes
diff --git a/bpf/accesslog/accesslog.c b/bpf/accesslog/accesslog.c
new file mode 100644
index 0000000..87b62dd
--- /dev/null
+++ b/bpf/accesslog/accesslog.c
@@ -0,0 +1,59 @@
+// 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 <bpf/bpf_endian.h>
+#include "api.h"
+#include "syscall_reading.h"
+#include "protocol_analyzer.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/sched.h>
+#include <linux/bpf.h>
+#include <linux/ptrace.h>
+#include <linux/socket.h>
+#include <asm/errno.h>
+#include <arpa/inet.h>
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+
+char __license[] SEC("license") = "Dual MIT/GPL";
+
+// process execution monitoring
+#include "process/process.c"
+
+// syscalls monitoring
+#include "syscalls/connect.c"
+#include "syscalls/transfer.c"
+#include "syscalls/close.c"
+
+// network l2-l4 monitoring
+#include "l24/write_l4.c"
+#include "l24/write_l3.c"
+#include "l24/write_l2.c"
+#include "l24/nf.c"
+#include "l24/read_l4.c"
+#include "l24/read_l3.c"
+#include "l24/read_l2.c"
+
+// tls monitoring
+#include "tls/go_tls.c"
+#include "tls/node_tls.c"
+#include "tls/openssl.c"
\ No newline at end of file
diff --git a/bpf/accesslog/common/connection.h b/bpf/accesslog/common/connection.h
new file mode 100644
index 0000000..eb51267
--- /dev/null
+++ b/bpf/accesslog/common/connection.h
@@ -0,0 +1,322 @@
+// 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.
+
+#pragma once
+
+#include "api.h"
+#include "socket.h"
+#include "data_args.h"
+#include "socket_opts.h"
+
+// syscall:connect
+struct connect_args_t {
+ __u32 fd;
+ __u32 fix;
+ struct sockaddr* addr;
+ struct sock *sock;
+ __u64 start_nacs;
+
+ struct connect_track_remote remote;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct connect_args_t);
+} conecting_args SEC(".maps");
+
+// syscall:accept
+struct accept_args_t {
+ struct sockaddr* addr;
+ struct socket* socket;
+ __u64 start_nacs;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct accept_args_t);
+} accepting_args SEC(".maps");
+
+// syscall:close
+struct sock_close_args_t {
+ int fd;
+ __u64 start_nacs;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct sock_close_args_t);
+} closing_args SEC(".maps");
+
+// notify to the user-space the connection connected(connect, accept)
+// only traced connection ipv4/v6 or unknown connection
+struct socket_connect_event_t {
+ // current connection id
+ __u64 conid;
+ // random value in one active connection
+ // generate a unique ID through connection_id + random_id, which is convenient for histogram data storage.
+ // we need random_id becase socketfd would be multiplexed in the same pid,
+ // but the metrics data(histogram) is MAP data, which can only be read by user-space with interval, so it would cause data delay.
+ __u64 random_id;
+ // connect operation start nanosecond
+ __u64 start_time;
+ // connect operation finish nanosecond
+ __u64 end_time;
+ // current process id
+ __u32 pid;
+ // current socket fd
+ __u32 sockfd;
+ // create from function name
+ __u8 func_name;
+
+ // the type of role in current connection
+ __u8 role;
+ // socket type
+ __u8 socket_family;
+ // is connect success or not
+ __u8 success;
+ __u32 __pad0;
+
+ // upstream
+ __u32 remote_addr_v4;
+ __u8 remote_addr_v6[16];
+ __u32 remote_port;
+ // downstream
+ __u32 local_addr_v4;
+ __u8 local_addr_v6[16];
+ __u32 local_port;
+
+ __u32 conntrack_upstream_port;
+ __u64 conntrack_upstream_iph;
+ __u64 conntrack_upstream_ipl;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} socket_connection_event_queue SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, __u32);
+ __type(value, struct socket_connect_event_t);
+ __uint(max_entries, 1);
+} socket_connect_event_per_cpu_map SEC(".maps");
+static __inline struct socket_connect_event_t* create_socket_connect_event() {
+ __u32 kZero = 0;
+ return bpf_map_lookup_elem(&socket_connect_event_per_cpu_map, &kZero);
+}
+
+// active connection cached into the hashmap
+// if connection closed, then deleted
+struct active_connection_t {
+ // random value in one active connection
+ // generate a unique ID through connection_id + random_id, which is convenient for histogram data storage
+ __u64 random_id;
+ // process id
+ __u32 pid;
+ // socket fd under process
+ __u32 sockfd;
+ // the type of role in current connection
+ __u32 role;
+ // socket type
+ __u32 socket_family;
+
+ // for protocol analyze
+ __u8 protocol;
+ // current connection is ssl
+ __u8 ssl;
+ // skip data upload when the protocol break(such as HTTP2)
+ __u8 skip_data_upload;
+ __u8 pad0;
+ __u32 pad1;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct active_connection_t);
+} active_connection_map SEC(".maps");
+static __inline __u64 gen_tgid_fd(__u32 tgid, __u32 sockfd) {
+ return ((__u64)tgid << 32) | sockfd;
+}
+struct socket_close_event_t {
+ // current connection id
+ __u64 conid;
+ // random value in one active connection
+ // generate a unique ID through connection_id + random_id, which is convenient for histogram data storage
+ __u64 random_id;
+
+ // close event execute time
+ __u64 start_time;
+ __u64 end_time;
+ // process id
+ __u32 pid;
+ // socket fd under process
+ __u32 sockfd;
+ // close success
+ __u32 success;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} socket_close_event_queue SEC(".maps");
+
+static __inline bool family_should_trace(const __u32 family) {
+ return family != AF_UNKNOWN && family != AF_INET && family != AF_INET6 ? false : true;
+}
+
+static __always_inline void submit_new_connection(void* ctx, bool success, __u32 func_name, __u32 tgid, __u32 fd, __u64 start_nacs,
+ struct sockaddr* addr, const struct socket* socket, struct connect_track_remote* conntrack, __u8 role) {
+ // send to the user-space the connection event
+ __u64 curr_nacs = bpf_ktime_get_ns();
+ struct socket_connect_event_t *event = create_socket_connect_event();
+ if (event == NULL) {
+ return;
+ }
+
+ __u64 conid = gen_tgid_fd(tgid, fd);
+ __u64 random_id = bpf_get_prandom_u32();
+ event->conid = conid;
+ event->random_id = random_id;
+ event->start_time = start_nacs;
+ event->end_time = curr_nacs;
+ event->func_name = func_name;
+ if (func_name == SOCKET_OPTS_TYPE_CONNECT) {
+ event->role = CONNECTION_ROLE_TYPE_CLIENT;
+ } else if (func_name == SOCKET_OPTS_TYPE_ACCEPT) {
+ event->role = CONNECTION_ROLE_TYPE_SERVER;
+ } else {
+ event->role = role;
+ }
+ event->pid = tgid;
+ event->sockfd = fd;
+
+ // cleanup and fill the conntrack
+ event->conntrack_upstream_iph = 0;
+ event->conntrack_upstream_ipl = 0;
+ event->conntrack_upstream_port = 0;
+ if (conntrack != NULL) {
+ event->conntrack_upstream_iph = conntrack->iph;
+ event->conntrack_upstream_ipl = conntrack->ipl;
+ event->conntrack_upstream_port = conntrack->port;
+ }
+ event->success = success;
+
+ __u16 port;
+ if (socket != NULL) {
+ // only get from accept function(server side)
+ struct sock* s;
+ BPF_CORE_READ_INTO(&s, socket, sk);
+
+ short unsigned int skc_family;
+ BPF_CORE_READ_INTO(&skc_family, s, __sk_common.skc_family);
+ event->socket_family = skc_family;
+
+ if (event->socket_family == AF_INET) {
+ BPF_CORE_READ_INTO(&port, s, __sk_common.skc_num);
+ event->local_port = port;
+ BPF_CORE_READ_INTO(&event->local_addr_v4, s, __sk_common.skc_rcv_saddr);
+ BPF_CORE_READ_INTO(&port, s, __sk_common.skc_dport);
+ event->remote_port = bpf_ntohs(port);
+ BPF_CORE_READ_INTO(&event->remote_addr_v4, s, __sk_common.skc_daddr);
+ } else if (event->socket_family == AF_INET6) {
+ BPF_CORE_READ_INTO(&port, s, __sk_common.skc_num);
+ event->local_port = port;
+ BPF_CORE_READ_INTO(&event->local_addr_v6, s, __sk_common.skc_v6_rcv_saddr.in6_u.u6_addr8);
+ BPF_CORE_READ_INTO(&port, s, __sk_common.skc_dport);
+ event->remote_port = bpf_ntohs(port);
+ BPF_CORE_READ_INTO(&event->remote_addr_v6, s, __sk_common.skc_v6_daddr.in6_u.u6_addr8);
+ }
+ } else if (addr != NULL) {
+ event->socket_family = _(addr->sa_family);
+ if (event->socket_family == AF_INET) {
+ struct sockaddr_in *daddr = (struct sockaddr_in *)addr;
+ bpf_probe_read(&event->remote_addr_v4, sizeof(event->remote_addr_v4), &daddr->sin_addr.s_addr);
+ bpf_probe_read(&port, sizeof(port), &daddr->sin_port);
+ event->remote_port = bpf_ntohs(port);
+ } else if (event->socket_family == AF_INET6) {
+ struct sockaddr_in6 *daddr = (struct sockaddr_in6 *)addr;
+ bpf_probe_read(&event->remote_addr_v6, sizeof(event->remote_addr_v6), &daddr->sin6_addr.s6_addr);
+ bpf_probe_read(&port, sizeof(port), &daddr->sin6_port);
+ event->remote_port = bpf_ntohs(port);
+ }
+ } else {
+ event->socket_family = AF_UNKNOWN;
+ }
+
+ bpf_perf_event_output(ctx, &socket_connection_event_queue, BPF_F_CURRENT_CPU, event, sizeof(*event));
+ if (success == false) {
+ return;
+ }
+
+ // if connect success, then add the activate connection into the kernel
+ // active connection save
+ struct active_connection_t con = {};
+ con.random_id = event->random_id;
+ con.pid = tgid;
+ con.sockfd = fd;
+ con.role = event->role;
+ con.socket_family = event->socket_family;
+ bpf_map_update_elem(&active_connection_map, &conid, &con, 0);
+}
+
+static __inline struct active_connection_t* get_or_create_active_conn(void *ctx, __u32 tgid, __u32 fd, __u32 func_name, __u8 role) {
+ __u64 conid = gen_tgid_fd(tgid, fd);
+ struct active_connection_t *conn = bpf_map_lookup_elem(&active_connection_map, &conid);
+ if (conn != NULL) {
+ return conn;
+ }
+ submit_new_connection(ctx, true, func_name, tgid, fd, 0, NULL, NULL, NULL, role);
+ return bpf_map_lookup_elem(&active_connection_map, &conid);
+}
+
+
+static __inline void submit_connection_when_not_exists(void *ctx, __u64 id, struct connect_args_t* connect_args, __u32 func_name, __u8 role) {
+ __u32 tgid = (__u32)(id >> 32);
+ __u32 fd = connect_args->fd;
+
+ __u64 conid = gen_tgid_fd(tgid, fd);
+ struct active_connection_t *conn = bpf_map_lookup_elem(&active_connection_map, &conid);
+ if (conn != NULL) {
+ return;
+ }
+ submit_new_connection(ctx, true, func_name, tgid, connect_args->fd, connect_args->start_nacs, connect_args->addr, NULL, &connect_args->remote, role);
+}
+
+static __inline void notify_close_connection(void* ctx, __u64 conid, struct active_connection_t* con, __u64 start_time, __u64 end_time, int ret) {
+ struct socket_close_event_t close_event = {};
+
+ close_event.conid = conid;
+ close_event.random_id = con->random_id;
+ close_event.start_time = start_time;
+ close_event.end_time = end_time;
+ close_event.pid = con->pid;
+ close_event.sockfd = con->sockfd;
+ close_event.success = ret > 0 ? true : false;
+
+ bpf_perf_event_output(ctx, &socket_close_event_queue, BPF_F_CURRENT_CPU, &close_event, sizeof(close_event));
+}
+
+static __inline void submit_close_connection(void* ctx, __u32 tgid, __u32 fd, __u64 start_nacs, int ret) {
+ __u64 curr_nacs = bpf_ktime_get_ns();
+ __u64 conid = gen_tgid_fd(tgid, fd);
+ struct active_connection_t* con = bpf_map_lookup_elem(&active_connection_map, &conid);
+ if (con == NULL) {
+ return;
+ }
+ notify_close_connection(ctx, conid, con, start_nacs, curr_nacs, ret);
+ bpf_map_delete_elem(&active_connection_map, &conid);
+}
\ No newline at end of file
diff --git a/bpf/accesslog/common/data_args.h b/bpf/accesslog/common/data_args.h
new file mode 100644
index 0000000..2d76062
--- /dev/null
+++ b/bpf/accesslog/common/data_args.h
@@ -0,0 +1,110 @@
+// 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.
+
+#pragma once
+
+#include "socket_opts.h"
+
+struct connect_track_remote {
+ __u64 iph;
+ __u64 ipl;
+ __u16 port;
+};
+
+struct sock_data_args_t {
+ __u32 fd;
+ // current read/write is calls on the sockets.
+ __u32 is_sock_event;
+ size_t iovlen;
+ unsigned int* msg_len;
+ __u64 start_nacs;
+ // buffer
+ char* buf;
+ struct iovec *iovec;
+ __u64 data_id;
+ // for openssl
+ __u32 excepted_size;
+ __u32 ifindex;
+ __u64 total_package_size;
+ __u8 package_count;
+ __u8 retransmit_package_count;
+ __u8 ssl_buffer_force_unfinished;
+ __u8 sk_role;
+ __u32 l2_enter_queue_count;
+ struct sk_buff *buffer;
+ __u64 enter_l4_time;
+ __u64 exit_l4_time;
+ __u64 l3_duration;
+ __u64 l3_rcv_duration;
+ __u64 l3_local_duration;
+ __u64 l3_output_duration;
+ __u32 total_resolve_mac_count;
+ __u32 total_net_filter_count;
+ __u64 total_resolve_mac_time;
+ __u64 total_net_filter_time;
+ __u64 total_package_to_queue_time;
+ __u64 total_package_receive_from_queue_time;
+
+ __u64 l2_duration;
+ __u64 l2_enter_queue_package_count;
+ __u64 l2_ready_send_duration;
+ __u64 l2_send_duration;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct sock_data_args_t);
+} socket_data_args SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, __u64);
+} socket_data_id_generate_map SEC(".maps");
+
+static __inline __u64 get_socket_data_id(__u8 from, __u64 id, __u32 fd) {
+ __u32 tgid = (__u32)(id >> 32);
+ __u64 key = ((__u64)tgid << 32) | fd;
+ __u64 *data_id = bpf_map_lookup_elem(&socket_data_id_generate_map, &key);
+ if (!data_id) {
+ return 0;
+ }
+ return *data_id;
+}
+
+static __inline __u64 generate_socket_data_id(__u64 id, __u32 fd, __u32 func_name, bool check) {
+ __u32 tgid = (__u32)(id >> 32);
+ __u64 key = ((__u64)tgid << 32) | fd;
+ if (check) {
+ if (tgid_should_trace(tgid) == false) {
+ return 0;
+ }
+ }
+ __u64 *data_id = bpf_map_lookup_elem(&socket_data_id_generate_map, &key);
+ if (!data_id) {
+ __u64 tmp = 0;
+ bpf_map_update_elem(&socket_data_id_generate_map, &key, &tmp, BPF_NOEXIST);
+ data_id = bpf_map_lookup_elem(&socket_data_id_generate_map, &key);
+ if (!data_id) {
+ return 0;
+ }
+ }
+ (*data_id)++;
+ return *data_id;
+}
\ No newline at end of file
diff --git a/bpf/profiling/continuous/skb.h b/bpf/accesslog/common/sock.h
similarity index 56%
copy from bpf/profiling/continuous/skb.h
copy to bpf/accesslog/common/sock.h
index ed1a9ed..d0a84ec 100644
--- a/bpf/profiling/continuous/skb.h
+++ b/bpf/accesslog/common/sock.h
@@ -15,28 +15,22 @@
// specific language governing permissions and limitations
// under the License.
-struct iovec {
- void *iov_base;
- __u64 iov_len;
-} __attribute__((preserve_access_index));
+#pragma once
+#include "api.h"
+#include "socket.h"
+#include "socket_opts.h"
-struct iov_iter {
- __u64 count;
- union {
- const struct iovec *iov;
- const struct kvec *kvec;
- const struct bio_vec *bvec;
- struct xarray *xarray;
- struct pipe_inode_info *pipe;
- };
-} __attribute__((preserve_access_index));
+static __always_inline __u8 get_sock_role(__u8 current_role, struct sock* sock) {
+ if (current_role != CONNECTION_ROLE_TYPE_UNKNOWN) {
+ return current_role;
+ }
+ // the max_ack_backlog holds the limit for the accept queue
+ // if it is a server, it will not be 0
+ int max_ack_backlog = 0;
+ if (0 != bpf_core_read(&max_ack_backlog, sizeof(max_ack_backlog),
+ &sock->sk_max_ack_backlog)) {
+ return CONNECTION_ROLE_TYPE_UNKNOWN;
+ }
-struct msghdr {
- struct iov_iter msg_iter; /* data */
- unsigned int msg_flags;
-} __attribute__((preserve_access_index));
-
-struct sock {
- struct socket *sk_socket;
- __u32 sk_max_ack_backlog;
-} __attribute__((preserve_access_index));
\ No newline at end of file
+ return max_ack_backlog == 0 ? CONNECTION_ROLE_TYPE_CLIENT : CONNECTION_ROLE_TYPE_SERVER;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/l24/l24.h b/bpf/accesslog/l24/l24.h
new file mode 100644
index 0000000..9ce716d
--- /dev/null
+++ b/bpf/accesslog/l24/l24.h
@@ -0,0 +1,139 @@
+// 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.
+
+#pragma once
+
+#include "api.h"
+#include "socket.h"
+#include "socket_opts.h"
+
+struct skb_receive_detail {
+ __u64 netif_receive_time;
+ __u64 enter_ip_rcv_time;
+ __u64 exit_ip_rcv_time;
+ __u64 ip_rcv_finish_time;
+ __u64 ip_local_time;
+ __u64 ip_local_finish_time;
+ __u64 enter_tcp_rcv_time;
+ __u64 exit_tcp_rcv_time;
+ __u64 enter_nf_time;
+ __u32 ifindex;
+ __u32 total_nf_count;
+ __u64 total_nf_time;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, struct sk_buff *);
+ __type(value, struct skb_receive_detail);
+} sk_buff_receive_detail_map SEC(".maps");
+
+struct skb_transmit_detail {
+ // l3
+ __u64 l3_enter_time;
+ __u64 l3_exit_time;
+ __u64 l3_local_time;
+ __u64 l3_output_time;
+ __u64 l3_finish_time;
+ __u16 total_nf_count;
+ __u16 total_resolve_neigh_count;
+ __u32 ifindex;
+ __u64 enter_nf_time;
+ __u64 enter_resolve_neigh_time;
+ __u64 total_nf_time;
+ __u64 total_resolve_neigh_time;
+
+ // l2
+ __u64 l2_enter_time;
+ __u64 l2_exit_time;
+ __u64 l2_start_xmit_time;
+ __u64 l2_finish_xmit_time;
+ // for loss package, for now, we only support first 4 locations, it could be changes to map-in-map
+ __u64 loss_package_location1;
+ __u64 loss_package_location2;
+ __u64 loss_package_location3;
+ __u64 loss_package_location4;
+ __u16 loss_package_count1;
+ __u16 loss_package_count2;
+ __u16 loss_package_count3;
+ __u16 loss_package_count4;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, struct sk_buff *);
+ __type(value, struct skb_transmit_detail);
+} sk_buff_transmit_detail_map SEC(".maps");
+
+#define L24_TEMP_ARGS_TRANSMIT_NF_HOOK_SLOW 1
+#define L24_TEMP_ARGS_NEIGHT_RESOLVE_OUTPUT 2
+#define L24_TEMP_ARGS_DEV_QUEUE_EMIT 3
+#define L24_TEMP_ARGS_IP_RCV 4
+#define L24_TEMP_ARGS_TCP_RCV 5
+#define L24_TEMP_ARGS_RCV_NF_HOOK_SLOW 1
+
+struct l24_tmp_args_key {
+ __u64 id;
+ __u64 type;
+};
+struct l24_tmp_args_value {
+ struct skb_transmit_detail *detail;
+ __u64 start_time;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, struct l24_tmp_args_key);
+ __type(value, struct sk_buff *);
+} sk_temp_args_map SEC(".maps");
+
+static __always_inline void save_l24_tmp_args(__u64 tpe, struct sk_buff *skb) {
+ struct l24_tmp_args_key key = {
+ .id = bpf_get_current_pid_tgid(),
+ .type = tpe,
+ };
+ bpf_map_update_elem(&sk_temp_args_map, &key, &skb, BPF_ANY);
+}
+
+static __always_inline struct skb_transmit_detail* get_l24_transmit_tmp_args(__u64 tpe) {
+ struct l24_tmp_args_key key = {
+ .id = bpf_get_current_pid_tgid(),
+ .type = tpe,
+ };
+ struct sk_buff* buff = bpf_map_lookup_elem(&sk_temp_args_map, &key);
+ if (buff == NULL) {
+ return NULL;
+ }
+ bpf_map_delete_elem(&sk_temp_args_map, &key);
+ return bpf_map_lookup_elem(&sk_buff_transmit_detail_map, buff);
+}
+
+static __always_inline struct skb_receive_detail* get_l24_rcv_tmp_args(__u64 tpe) {
+ struct l24_tmp_args_key key = {
+ .id = bpf_get_current_pid_tgid(),
+ .type = tpe,
+ };
+ struct sk_buff* buff = bpf_map_lookup_elem(&sk_temp_args_map, &key);
+ if (buff == NULL) {
+ return NULL;
+ }
+ bpf_map_delete_elem(&sk_temp_args_map, &key);
+ return bpf_map_lookup_elem(&sk_buff_receive_detail_map, buff);
+}
\ No newline at end of file
diff --git a/bpf/accesslog/l24/nf.c b/bpf/accesslog/l24/nf.c
new file mode 100644
index 0000000..1e855cd
--- /dev/null
+++ b/bpf/accesslog/l24/nf.c
@@ -0,0 +1,54 @@
+// 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 "api.h"
+#include "l24.h"
+
+SEC("kprobe/nf_hook_slow")
+int nf_hook_slow(struct pt_regs * ctx) {
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_transmit_detail *transmit_detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (transmit_detail != NULL) {
+ transmit_detail->enter_nf_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_TRANSMIT_NF_HOOK_SLOW, skb);
+ return 0;
+ }
+ struct skb_receive_detail *recv_detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (recv_detail != NULL) {
+ recv_detail->enter_nf_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_RCV_NF_HOOK_SLOW, skb);
+ return 0;
+ }
+ return 0;
+}
+
+SEC("kretprobe/nf_hook_slow")
+int nf_hook_slow_ret(struct pt_regs * ctx) {
+ struct skb_transmit_detail *transmit_detail = get_l24_transmit_tmp_args(L24_TEMP_ARGS_TRANSMIT_NF_HOOK_SLOW);
+ if (transmit_detail != NULL) {
+ transmit_detail->total_nf_count++;
+ transmit_detail->total_nf_time = bpf_ktime_get_ns() - transmit_detail->enter_nf_time;
+ return 0;
+ }
+ struct skb_receive_detail* rcv_detail = get_l24_rcv_tmp_args(L24_TEMP_ARGS_RCV_NF_HOOK_SLOW);
+ if (rcv_detail != NULL) {
+ rcv_detail->total_nf_count++;
+ rcv_detail->total_nf_time = bpf_ktime_get_ns() - rcv_detail->enter_nf_time;
+ return 0;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/pkg/boot/register.go b/bpf/accesslog/l24/read_l2.c
similarity index 56%
copy from pkg/boot/register.go
copy to bpf/accesslog/l24/read_l2.c
index 8f0d64d..0896eeb 100644
--- a/pkg/boot/register.go
+++ b/bpf/accesslog/l24/read_l2.c
@@ -15,20 +15,26 @@
// specific language governing permissions and limitations
// under the License.
-package boot
+#include "l24.h"
+#include "../common/data_args.h"
-import (
- "github.com/apache/skywalking-rover/pkg/core"
- "github.com/apache/skywalking-rover/pkg/logger"
- "github.com/apache/skywalking-rover/pkg/module"
- "github.com/apache/skywalking-rover/pkg/process"
- "github.com/apache/skywalking-rover/pkg/profiling"
-)
+struct netif_receive_skb {
+ unsigned long long pad;
+ void * skbaddr;
+};
-func init() {
- // register all active module
- module.Register(logger.NewModule())
- module.Register(core.NewModule())
- module.Register(process.NewModule())
- module.Register(profiling.NewModule())
+SEC("tracepoint/net/netif_receive_skb")
+int tracepoint_netif_receive_skb(struct netif_receive_skb *ctx) {
+ struct sk_buff * skb = (struct sk_buff *)ctx->skbaddr;
+
+ struct net_device *device = _(skb->dev);
+ int ifindex;
+ bpf_probe_read(&ifindex, sizeof(ifindex), &device->ifindex);
+
+ struct skb_receive_detail detail = {
+ .ifindex = ifindex,
+ .netif_receive_time = bpf_ktime_get_ns(),
+ };
+ bpf_map_update_elem(&sk_buff_receive_detail_map, &skb, &detail, 0);
+ return 0;
}
diff --git a/bpf/accesslog/l24/read_l3.c b/bpf/accesslog/l24/read_l3.c
new file mode 100644
index 0000000..9779344
--- /dev/null
+++ b/bpf/accesslog/l24/read_l3.c
@@ -0,0 +1,176 @@
+// 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 "l24.h"
+#include "../common/data_args.h"
+#include "list.h"
+
+SEC("kprobe/ip_rcv")
+int ip_rcv(struct pt_regs * ctx) {
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->enter_ip_rcv_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_IP_RCV, skb);
+ }
+ return 0;
+}
+
+SEC("kretprobe/ip_rcv")
+int ip_rcv_ret(struct pt_regs * ctx) {
+ struct skb_receive_detail* detail = get_l24_rcv_tmp_args(L24_TEMP_ARGS_IP_RCV);
+ if (detail != NULL) {
+ detail->exit_ip_rcv_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct bpf_list_head);
+} ip_list_rcv_args_map SEC(".maps");
+
+#define ip_list_foreach_skb(loc, time) \
+ list_for_each_entry_data(skb, next, head, list) { \
+ detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb); \
+ if (detail != NULL) { \
+ detail->loc = time; \
+ skb_list = append_bpf_list_head(&skb_list, skb); \
+ } \
+ };
+
+#define bpf_list_foreach_skb(loc, time) \
+ bpf_list_for_each_foreach(skb, head) { \
+ detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb); \
+ if (detail != NULL) { \
+ detail->loc = time; \
+ } \
+ };
+
+SEC("kprobe/ip_list_rcv")
+int ip_list_rcv(struct pt_regs * ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct list_head *head = (struct list_head *)PT_REGS_PARM1(ctx);
+ if (head == NULL) {
+ return 0;
+ }
+ __u64 enter_rcv_time = bpf_ktime_get_ns();
+ struct skb_receive_detail *detail = NULL;
+
+ struct sk_buff *skb = NULL, *next = NULL;
+ struct bpf_list_head skb_list = init_bpf_list_head();
+ list_for_each_entry_init()
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+ ip_list_foreach_skb(enter_ip_rcv_time, enter_rcv_time)
+
+
+ bpf_map_update_elem(&ip_list_rcv_args_map, &id, &skb_list, BPF_ANY);
+ return 0;
+}
+
+SEC("kretprobe/ip_list_rcv")
+int ip_list_rcv_ret(struct pt_regs * ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct bpf_list_head *head = bpf_map_lookup_elem(&ip_list_rcv_args_map, &id);
+ if (head == NULL) {
+ return 0;
+ }
+
+ struct sk_buff *skb = NULL;
+ bpf_list_for_each_init()
+ struct skb_receive_detail *detail = NULL;
+ __u64 exit_rcv_time = bpf_ktime_get_ns();
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+ bpf_list_foreach_skb(exit_ip_rcv_time, exit_rcv_time)
+
+ bpf_map_delete_elem(&ip_list_rcv_args_map, &id);
+ return 0;
+}
+
+SEC("kprobe/ip_rcv_finish")
+int ip_rcv_finish(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->ip_rcv_finish_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("kprobe/ip_sublist_rcv_finish")
+int ip_sublist_rcv_finish(struct pt_regs * ctx) {
+ struct list_head *head = (struct list_head *)PT_REGS_PARM1(ctx);
+ if (head == NULL) {
+ return 0;
+ }
+ __u64 rcv_finish_time = bpf_ktime_get_ns();
+ struct skb_receive_detail *detail = NULL;
+
+ struct sk_buff *skb = NULL, *next = NULL;
+ struct bpf_list_head skb_list = init_bpf_list_head();
+ list_for_each_entry_init()
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+ ip_list_foreach_skb(ip_rcv_finish_time, rcv_finish_time)
+
+ return 0;
+}
+
+SEC("kprobe/ip_local_deliver")
+int ip_local_deliver(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->ip_local_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("kprobe/ip_local_deliver_finish")
+int ip_local_deliver_finish(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM3(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->ip_local_finish_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
diff --git a/bpf/accesslog/l24/read_l4.c b/bpf/accesslog/l24/read_l4.c
new file mode 100644
index 0000000..5a46d72
--- /dev/null
+++ b/bpf/accesslog/l24/read_l4.c
@@ -0,0 +1,59 @@
+// 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 "l24.h"
+#include "../common/data_args.h"
+
+SEC("kprobe/tcp_v4_rcv")
+int tcp_v4_rcv(struct pt_regs * ctx) {
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->enter_tcp_rcv_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_TCP_RCV, skb);
+ }
+ return 0;
+}
+
+SEC("kretprobe/tcp_v4_rcv")
+int tcp_v4_rcv_ret(struct pt_regs * ctx) {
+ struct skb_receive_detail* detail = get_l24_rcv_tmp_args(L24_TEMP_ARGS_TCP_RCV);
+ if (detail != NULL) {
+ detail->exit_tcp_rcv_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("kprobe/tcp_v6_rcv")
+int tcp_v6_rcv(struct pt_regs * ctx) {
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &skb);
+ if (detail != NULL) {
+ detail->enter_tcp_rcv_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_TCP_RCV, skb);
+ }
+ return 0;
+}
+
+SEC("kretprobe/tcp_v6_rcv")
+int tcp_v6_rcv_ret(struct pt_regs * ctx) {
+ struct skb_receive_detail* detail = get_l24_rcv_tmp_args(L24_TEMP_ARGS_TCP_RCV);
+ if (detail != NULL) {
+ detail->exit_tcp_rcv_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
diff --git a/bpf/accesslog/l24/write_l2.c b/bpf/accesslog/l24/write_l2.c
new file mode 100644
index 0000000..2f477df
--- /dev/null
+++ b/bpf/accesslog/l24/write_l2.c
@@ -0,0 +1,72 @@
+// 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 "l24.h"
+#include "../common/data_args.h"
+
+struct net_dev_start_xmit_args {
+ unsigned long pad0;
+ unsigned long pad1;
+
+ void *skb;
+};
+
+struct net_dev_xmit_args {
+ unsigned long pad0;
+
+ void *skb;
+};
+
+SEC("kprobe/__dev_queue_xmit")
+int dev_queue_emit(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->l2_enter_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_DEV_QUEUE_EMIT, skb);
+ }
+ return 0;
+}
+
+SEC("kretprobe/__dev_queue_xmit")
+int dev_queue_emit_ret(struct pt_regs * ctx){
+ struct skb_transmit_detail *detail = get_l24_transmit_tmp_args(L24_TEMP_ARGS_DEV_QUEUE_EMIT);
+ if (detail != NULL) {
+ detail->l2_exit_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("tracepoint/net/net_dev_start_xmit")
+int tracepoint_net_dev_start_xmit(struct net_dev_start_xmit_args *args) {
+ struct sk_buff * skb = args->skb;
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->l2_start_xmit_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("tracepoint/net/net_dev_xmit")
+int tracepoint_net_dev_xmit(struct net_dev_xmit_args *args) {
+ struct sk_buff * skb = args->skb;
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->l2_finish_xmit_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/l24/write_l3.c b/bpf/accesslog/l24/write_l3.c
new file mode 100644
index 0000000..57ba28a
--- /dev/null
+++ b/bpf/accesslog/l24/write_l3.c
@@ -0,0 +1,147 @@
+// 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 "l24.h"
+#include "../common/data_args.h"
+
+SEC("kprobe/__ip_queue_xmit")
+int ip_queue_xmit(struct pt_regs * ctx){
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM2(ctx);
+ // update current transmit skb
+ data_args->buffer = skb;
+
+ // adding skb detail into map(for getting all l2-3 detail from skb)
+ struct skb_transmit_detail detail = {};
+ detail.l3_enter_time = bpf_ktime_get_ns();
+ bpf_map_update_elem(&sk_buff_transmit_detail_map, &skb, &detail, 0);
+ }
+ return 0;
+}
+
+SEC("kretprobe/__ip_queue_xmit")
+int ip_queue_xmit_ret(struct pt_regs * ctx){
+ __u64 id = bpf_get_current_pid_tgid();
+ // getting skb
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args == NULL) {
+ return 0;
+ }
+ // getting all l2-3 detail
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &data_args->buffer);
+ if (detail == NULL) {
+ return 0;
+ }
+
+ data_args->l3_duration += bpf_ktime_get_ns() - detail->l3_enter_time;
+ if (detail->l3_output_time > 0 && detail->l3_local_time > 0) {
+ data_args->l3_local_duration += detail->l3_output_time - detail->l3_local_time;
+ }
+ if (detail->l3_finish_time > 0 && detail->l3_output_time > 0) {
+ data_args->l3_output_duration += detail->l3_finish_time - detail->l3_output_time;
+ }
+ data_args->total_resolve_mac_count = detail->total_resolve_neigh_count;
+ data_args->total_resolve_mac_time = detail->total_resolve_neigh_time;
+ data_args->total_net_filter_count = detail->total_nf_count;
+ data_args->total_net_filter_time = detail->total_nf_time;
+
+ if (detail->l2_enter_time > 0 && detail->l2_exit_time > 0) {
+ data_args->l2_duration = detail->l2_exit_time - detail->l2_enter_time;
+ data_args->l2_enter_queue_count++;
+ }
+ data_args->ifindex = _(detail->ifindex);
+ if (detail->l2_enter_time > 0) {
+ data_args->l2_enter_queue_package_count++;
+ }
+ if (detail->l2_start_xmit_time > 0 && detail->l2_enter_time > 0) {
+ data_args->l2_ready_send_duration += detail->l2_start_xmit_time - detail->l2_enter_time;
+ }
+ if (detail->l2_finish_xmit_time > 0 && detail->l2_start_xmit_time > 0) {
+ data_args->l2_send_duration += detail->l2_finish_xmit_time - detail->l2_start_xmit_time;
+ }
+ return 0;
+}
+
+SEC("kprobe/ip_local_out")
+int ip_local(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM3(ctx);
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->l3_local_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct sk_buff *);
+} ip_output_temp SEC(".maps");
+
+
+SEC("kprobe/ip_output")
+int ip_output(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM3(ctx);
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->l3_output_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("kprobe/ip_finish_output2")
+int ip_finish_output2(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM3(ctx);
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ long unsigned int _skb_refdst;
+ bpf_probe_read(&_skb_refdst, sizeof(_skb_refdst), &skb->_skb_refdst);
+ struct dst_entry *entry = (void *)(_skb_refdst & SKB_DST_PTRMASK);
+ struct net_device *device;
+ bpf_probe_read(&device, sizeof(device), &entry->dev);
+
+ int ifindex;
+ bpf_probe_read(&ifindex, sizeof(ifindex), &device->ifindex);
+ detail->ifindex = ifindex;
+ detail->l3_finish_time = bpf_ktime_get_ns();
+ }
+ return 0;
+}
+
+SEC("kprobe/neigh_resolve_output")
+int neigh_resolve_output(struct pt_regs * ctx){
+ struct sk_buff * skb = (struct sk_buff *)PT_REGS_PARM2(ctx);
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ detail->enter_resolve_neigh_time = bpf_ktime_get_ns();
+ save_l24_tmp_args(L24_TEMP_ARGS_NEIGHT_RESOLVE_OUTPUT, skb);
+ }
+ return 0;
+}
+
+SEC("kretprobe/neigh_resolve_output")
+int neigh_resolve_output_ret(struct pt_regs * ctx){
+ struct skb_transmit_detail *detail = get_l24_transmit_tmp_args(L24_TEMP_ARGS_NEIGHT_RESOLVE_OUTPUT);
+ if (detail != NULL) {
+ detail->total_resolve_neigh_count++;
+ detail->total_resolve_neigh_time = bpf_ktime_get_ns() - detail->enter_resolve_neigh_time;
+ }
+ return 0;
+}
diff --git a/bpf/accesslog/l24/write_l4.c b/bpf/accesslog/l24/write_l4.c
new file mode 100644
index 0000000..c38ecc6
--- /dev/null
+++ b/bpf/accesslog/l24/write_l4.c
@@ -0,0 +1,103 @@
+// 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 "l24.h"
+#include "../common/data_args.h"
+#include "../common/sock.h"
+
+struct kfree_skb_args {
+ unsigned long pad;
+
+ void *skb;
+ void *location;
+};
+
+SEC("kprobe/tcp_sendmsg")
+int tcp_sendmsg(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ data_args->enter_l4_time = bpf_ktime_get_ns();
+
+ // getting the socket role is client or server
+ struct sock *sk = (void *)PT_REGS_PARM1(ctx);
+ data_args->sk_role = get_sock_role(data_args->sk_role, sk);
+ }
+ return 0;
+};
+
+SEC("kretprobe/tcp_sendmsg")
+int tcp_sendmsg_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ data_args->exit_l4_time = bpf_ktime_get_ns();
+ }
+ return 0;
+};
+
+SEC("kprobe/tcp_transmit_skb")
+int tcp_transmit_skb(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ struct sk_buff *skb = (void *)PT_REGS_PARM2(ctx);
+ data_args->package_count++;
+ data_args->total_package_size += _(skb->len);
+ }
+ return 0;
+};
+
+SEC("tracepoint/tcp/tcp_retransmit_skb")
+int tracepoint_tcp_retransmit_skb() {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ data_args->retransmit_package_count++;
+ }
+ return 0;
+}
+
+#define UPDATE_LOSS_PACKAGE(detail, loc, count, location) \
+ if ((detail)->loc == 0) { \
+ (detail)->loc = (__u64)(location); \
+ (detail)->count = 1; \
+ return 0; \
+ } else if ((detail)->loc == (__u64)(location)) { \
+ (detail)->count++; \
+ return 0; \
+ }
+
+SEC("tracepoint/skb/kfree_skb")
+int kfree_skb(struct kfree_skb_args *args) {
+ struct sk_buff *skb = args->skb;
+ if (skb == NULL) {
+ return 0;
+ }
+ void* location = args->location;
+ if (location == NULL) {
+ return 0;
+ }
+ struct skb_transmit_detail *detail = bpf_map_lookup_elem(&sk_buff_transmit_detail_map, &skb);
+ if (detail != NULL) {
+ UPDATE_LOSS_PACKAGE(detail, loss_package_location1, loss_package_count1, location);
+ UPDATE_LOSS_PACKAGE(detail, loss_package_location2, loss_package_count2, location);
+ UPDATE_LOSS_PACKAGE(detail, loss_package_location3, loss_package_count3, location);
+ UPDATE_LOSS_PACKAGE(detail, loss_package_location4, loss_package_count4, location);
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/pkg/tools/host/network.go b/bpf/accesslog/process/process.c
similarity index 50%
copy from pkg/tools/host/network.go
copy to bpf/accesslog/process/process.c
index 34f24de..bdd29ed 100644
--- a/pkg/tools/host/network.go
+++ b/bpf/accesslog/process/process.c
@@ -15,48 +15,35 @@
// specific language governing permissions and limitations
// under the License.
-package host
+#include "api.h"
+#include "process.h"
-import (
- "net"
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} process_execute_queue SEC(".maps");
- "github.com/apache/skywalking-rover/pkg/logger"
-)
+struct process_execute_event {
+ __u32 pid;
+};
-var interfaces map[int]*net.Interface
-var log = logger.GetLogger("tools", "host")
+struct sched_comm_fork_ctx {
+ __u64 __pad_0;
+ char parent_comm[16];
+ __u32 parent_pid;
+ char child_comm[16];
+ __u32 child_pid;
+};
-func init() {
- if err := refreshInterfaces(); err != nil {
- panic(err)
- }
-}
+SEC("tracepoint/sched/sched_process_fork")
+int tracepoint_sched_process_fork(struct sched_comm_fork_ctx* ctx) {
+ __u32 tgid = ctx->parent_pid;
+ // adding to the monitor
+ __u32 v = 1;
+ bpf_map_update_elem(&process_monitor_control, &tgid, &v, 0);
-func NetworkName(ifindex int) string {
- i := interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- if e := refreshInterfaces(); e != nil {
- log.Warnf("error to refresh interfaces: %v", e)
- return ""
- }
- i = interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- return ""
-}
-
-func refreshInterfaces() error {
- results, err := net.Interfaces()
- if err != nil {
- return err
- }
- tmp := make(map[int]*net.Interface)
- for _, interf := range results {
- tmp[interf.Index] = &interf
- }
- interfaces = tmp
- return nil
-}
+ // send to the user-space to check the pid should monitor or not
+ struct process_execute_event event = {};
+ event.pid = tgid;
+ bpf_perf_event_output(ctx, &process_execute_queue, BPF_F_CURRENT_CPU, &event, sizeof(event));
+ return 0;
+}
\ No newline at end of file
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/bpf/accesslog/process/process.h
similarity index 68%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to bpf/accesslog/process/process.h
index 555705c..33c35e7 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/bpf/accesslog/process/process.h
@@ -15,11 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package enums
+#pragma once
-type ParseResult int
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u32);
+ __type(value, __u32);
+} process_monitor_control SEC(".maps");
-const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
-)
+static __inline bool tgid_should_trace(__u32 tgid) {
+ __u32 *val = bpf_map_lookup_elem(&process_monitor_control, &tgid);
+ if (!val) {
+ return false;
+ }
+ return (*val) == 1 ? true : false;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/syscalls/close.c b/bpf/accesslog/syscalls/close.c
new file mode 100644
index 0000000..d4539c6
--- /dev/null
+++ b/bpf/accesslog/syscalls/close.c
@@ -0,0 +1,70 @@
+// 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 "api.h"
+#include "socket.h"
+#include "socket_opts.h"
+#include "../process/process.h"
+#include "../common/connection.h"
+
+struct trace_point_enter_close {
+ __u64 pad_0;
+ int __syscall_nr;
+ __u32 pad_1;
+ int fd;
+};
+struct trace_point_exit_close {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ __u64 ret;
+};
+
+static __inline void process_close_sock(void* ctx, __u64 id, struct sock_close_args_t *args, int ret) {
+ __u32 tgid = (__u32)(id >> 32);
+ if (args->fd < 0) {
+ return;
+ }
+
+ submit_close_connection(ctx, tgid, args->fd, args->start_nacs, ret);
+}
+
+SEC("tracepoint/syscalls/sys_enter_close")
+int tracepoint_enter_close(struct trace_point_enter_close *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct sock_close_args_t close_args = {};
+ close_args.fd = ctx->fd;
+ close_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&closing_args, &id, &close_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_close")
+int tracepoint_exit_close(struct trace_point_exit_close *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_close_args_t *close_args = bpf_map_lookup_elem(&closing_args, &id);
+ if (close_args) {
+ process_close_sock(ctx, id, close_args, ctx->ret);
+ }
+
+ bpf_map_delete_elem(&closing_args, &id);
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/syscalls/connect.c b/bpf/accesslog/syscalls/connect.c
new file mode 100644
index 0000000..30a4a7f
--- /dev/null
+++ b/bpf/accesslog/syscalls/connect.c
@@ -0,0 +1,149 @@
+// 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 "api.h"
+#include "socket.h"
+#include "socket_opts.h"
+#include "../process/process.h"
+#include "../common/connection.h"
+
+struct trace_point_enter_connect {
+ __u64 pad_0;
+ int __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct sockaddr * uservaddr;
+};
+struct trace_point_exit_connect {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ __u64 ret;
+};
+
+struct trace_point_enter_accept {
+ __u64 pad_0;
+ int __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct sockaddr * upeer_sockaddr;
+};
+struct trace_point_exit_accept {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ long ret;
+};
+
+static __inline void process_connect(void *ctx, __u64 id, struct connect_args_t *connect_args, long ret) {
+ bool success = true;
+ if (ret < 0 && ret != -EINPROGRESS) {
+ success = false;
+ }
+ if (connect_args->fd < 0) {
+ return;
+ }
+ __u32 tgid = id >> 32;
+ struct sock *sock = connect_args->sock;
+ struct socket *s = _(sock->sk_socket);
+ submit_new_connection(ctx, success, SOCKET_OPTS_TYPE_CONNECT, tgid, connect_args->fd, connect_args->start_nacs, connect_args->addr, s, &connect_args->remote, 0);
+}
+
+static __inline void process_accept(void *ctx, __u64 id, struct accept_args_t *accept_args, long ret) {
+ int fd = (int) ret;
+ __u32 tgid = id >> 32;
+ struct socket *s = accept_args->socket;
+ submit_new_connection(ctx, true, SOCKET_OPTS_TYPE_ACCEPT, tgid, fd, accept_args->start_nacs, accept_args->addr, s, NULL, 0);
+}
+
+SEC("tracepoint/syscalls/sys_enter_connect")
+int tracepoint_enter_connect(struct trace_point_enter_connect *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct connect_args_t connect_args = {};
+ connect_args.fd = ctx->fd;
+ connect_args.addr = ctx->uservaddr;
+ connect_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_connect")
+int tracepoint_exit_connect(struct trace_point_exit_connect *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct connect_args_t *connect_args;
+
+ connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args) {
+ process_connect(ctx, id, connect_args, ctx->ret);
+ }
+
+ bpf_map_delete_elem(&conecting_args, &id);
+ return 0;
+}
+
+SEC("kprobe/tcp_connect")
+int tcp_connect(struct pt_regs *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);;
+ if (connect_args) {
+ connect_args->sock = (void *)PT_REGS_PARM1(ctx);
+ }
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_accept")
+int tracepoint_enter_accept(struct trace_point_enter_accept *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct accept_args_t accept_args = {};
+ accept_args.addr = ctx->upeer_sockaddr;
+ accept_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&accepting_args, &id, &accept_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_accept")
+int tracepoint_exit_accept(struct trace_point_exit_accept *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct accept_args_t *accept_args = bpf_map_lookup_elem(&accepting_args, &id);
+ if (accept_args) {
+ process_accept(ctx, id, accept_args, ctx->ret);
+ }
+
+ bpf_map_delete_elem(&accepting_args, &id);
+ return 0;
+}
+
+SEC("kretprobe/sock_alloc")
+int sock_alloc_ret(struct pt_regs *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct accept_args_t *accept_sock = bpf_map_lookup_elem(&accepting_args, &id);
+ if (accept_sock) {
+ struct socket *sock = (struct socket*)PT_REGS_RC(ctx);
+ accept_sock->socket = sock;
+ }
+ return 0;
+}
+
+#include "connect_conntrack.c"
\ No newline at end of file
diff --git a/bpf/accesslog/syscalls/connect_conntrack.c b/bpf/accesslog/syscalls/connect_conntrack.c
new file mode 100644
index 0000000..483599b
--- /dev/null
+++ b/bpf/accesslog/syscalls/connect_conntrack.c
@@ -0,0 +1,117 @@
+// 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 "connect_conntrack.h"
+#include "../common/data_args.h"
+
+static __always_inline void nf_conntrack_read_in6_addr(__u64 *addr_h, __u64 *addr_l, const struct in6_addr *in6) {
+ BPF_CORE_READ_INTO(addr_h, in6, s6_addr32[0]);
+ BPF_CORE_READ_INTO(addr_l, in6, s6_addr32[2]);
+}
+static __always_inline int nf_conntrack_tuple_to_conntrack_tuple(conntrack_tuple_t *t, const struct nf_conntrack_tuple *ct) {
+ __builtin_memset(t, 0, sizeof(conntrack_tuple_t));
+
+ switch (ct->dst.protonum) {
+ case IPPROTO_TCP:
+ t->sport = ct->src.u.tcp.port;
+ t->dport = ct->dst.u.tcp.port;
+ break;
+ case IPPROTO_UDP:
+ t->sport = ct->src.u.udp.port;
+ t->dport = ct->dst.u.udp.port;
+ break;
+ default:
+ return 0;
+ }
+
+ t->sport = bpf_ntohs(t->sport);
+ t->dport = bpf_ntohs(t->dport);
+ if (t->sport == 0 || t->dport == 0) {
+ return 0;
+ }
+
+ if (ct->src.l3num == AF_INET) {
+ t->saddr_l = ct->src.u3.ip;
+ t->daddr_l = ct->dst.u3.ip;
+
+ if (!t->saddr_l || !t->daddr_l) {
+ return 0;
+ }
+// } else if (ct->src.l3num == AF_INET6) {
+// nf_conntrack_read_in6_addr(&t->saddr_h, &t->saddr_l, &ct->src.u3.in6);
+// nf_conntrack_read_in6_addr(&t->daddr_h, &t->daddr_l, &ct->dst.u3.in6);
+//
+// if (!t->saddr_h || !t->saddr_l || !t->daddr_h || !t->daddr_l) {
+// return 0;
+// }
+ }
+ return 1;
+}
+
+static __always_inline int nf_conn_aware(struct pt_regs* ctx, struct nf_conn *ct) {
+ if (ct == NULL) {
+ return 0;
+ }
+ __u64 id = bpf_get_current_pid_tgid();
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (!connect_args) {
+ return 0;
+ }
+
+ __u32 status;
+ if (bpf_probe_read(&status, sizeof(status), &(ct->status)) != 0) {
+ return 0; // Invalid ct pointer
+ }
+
+ if (!(status & IPS_CONFIRMED)) {
+ return 0;
+ }
+ if (!(status & IPS_NAT_MASK)) {
+ return 0;
+ }
+
+ struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+ if (bpf_probe_read(&tuplehash, sizeof(tuplehash), &(ct->tuplehash)) != 0) {
+ return 0; // Invalid ct pointer
+ }
+
+ struct nf_conntrack_tuple reply = tuplehash[IP_CT_DIR_REPLY].tuple;
+
+ conntrack_tuple_t reply_conn = {};
+ if (!nf_conntrack_tuple_to_conntrack_tuple(&reply_conn, &reply)) {
+ return 0;
+ }
+
+ struct connect_track_remote remote = {};
+ remote.iph = reply_conn.saddr_h;
+ remote.ipl = reply_conn.saddr_l;
+ remote.port = reply_conn.sport;
+ connect_args->remote = remote;
+ bpf_map_update_elem(&conecting_args, &id, connect_args, 0);
+
+ return 0;
+}
+
+SEC("kprobe/__nf_conntrack_hash_insert")
+int nf_conntrack_hash_insert(struct pt_regs* ctx) {
+ return nf_conn_aware(ctx, (struct nf_conn*)PT_REGS_PARM1(ctx));
+}
+
+SEC("kprobe/nf_confirm")
+int nf_confirm(struct pt_regs* ctx) {
+ return nf_conn_aware(ctx, (struct nf_conn*)PT_REGS_PARM3(ctx));
+}
diff --git a/bpf/accesslog/syscalls/connect_conntrack.h b/bpf/accesslog/syscalls/connect_conntrack.h
new file mode 100644
index 0000000..0e67b9c
--- /dev/null
+++ b/bpf/accesslog/syscalls/connect_conntrack.h
@@ -0,0 +1,99 @@
+// 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 <linux/types.h>
+
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+
+typedef struct {
+ /* Using the type unsigned __int128 generates an error in the ebpf verifier */
+ __u64 saddr_h;
+ __u64 saddr_l;
+ __u64 daddr_h;
+ __u64 daddr_l;
+ __u16 sport;
+ __u16 dport;
+ __u32 netns;
+ // Metadata description:
+ // First bit indicates if the connection is TCP (1) or UDP (0)
+ // Second bit indicates if the connection is V6 (1) or V4 (0)
+ __u32 metadata; // This is that big because it seems that we atleast need a 32-bit aligned struct
+
+ __u32 _pad;
+} conntrack_tuple_t;
+
+
+struct nf_conntrack_man {
+ union nf_inet_addr u3;
+ union nf_conntrack_man_proto u;
+ /* Layer 3 protocol */
+ u_int16_t l3num;
+} __attribute__((preserve_access_index));
+
+
+struct nf_conntrack_tuple {
+ struct nf_conntrack_man src;
+ /* These are the parts of the tuple which are fixed. */
+ struct {
+ union nf_inet_addr u3;
+ union {
+ /* Add other protocols here. */
+ __be16 all;
+
+ struct {
+ __be16 port;
+ } tcp;
+ struct {
+ __be16 port;
+ } udp;
+ struct {
+ u_int8_t type, code;
+ } icmp;
+ struct {
+ __be16 port;
+ } dccp;
+ struct {
+ __be16 port;
+ } sctp;
+ struct {
+ __be16 key;
+ } gre;
+ } u;
+
+ /* The protocol. */
+ u_int8_t protonum;
+
+ /* The direction (for tuplehash) */
+ u_int8_t dir;
+ } dst;
+} __attribute__((preserve_access_index));
+
+struct hlist_nulls_node {
+ struct hlist_nulls_node *next, **pprev;
+} __attribute__((preserve_access_index));
+
+struct nf_conntrack_tuple_hash {
+ struct hlist_nulls_node hnnode;
+ struct nf_conntrack_tuple tuple;
+} __attribute__((preserve_access_index));
+
+struct nf_conn {
+ __u32 timeout;
+ struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+ long unsigned int status;
+ __u32 mark;
+} __attribute__((preserve_access_index));
diff --git a/bpf/accesslog/syscalls/transfer.c b/bpf/accesslog/syscalls/transfer.c
new file mode 100644
index 0000000..23e01da
--- /dev/null
+++ b/bpf/accesslog/syscalls/transfer.c
@@ -0,0 +1,634 @@
+// 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 "api.h"
+#include "socket_opts.h"
+#include "../process/process.h"
+#include "../common/data_args.h"
+#include "../common/sock.h"
+#include "../l24/l24.h"
+#include "transfer.h"
+
+struct trace_point_common_exit {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ __u64 ret;
+};
+struct trace_point_common_write {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ char * buf;
+ size_t count;
+};
+struct trace_point_common_writev {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct iovec * vec;
+ size_t count;
+};
+struct trace_point_common_readv {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct iovec * vec;
+ size_t count;
+};
+struct trace_point_common_sendmsg {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct user_msghdr * msg;
+};
+struct trace_point_common_sendmmsg {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct mmsghdr * mmsg;
+ unsigned int vlen;
+};
+struct trace_point_enter_sendto {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ char * buf;
+ size_t count;
+ unsigned int flags;
+ struct sockaddr * addr;
+};
+struct trace_point_enter_recvfrom {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ char * buf;
+ size_t count;
+ unsigned int flags;
+ struct sockaddr * addr;
+};
+struct trace_point_common_recvmsg {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct user_msghdr * msg;
+};
+struct trace_point_common_recvmmsg {
+ __u64 pad_0;
+ __u32 __syscall_nr;
+ __u32 pad_1;
+ int fd;
+ struct mmsghdr * mmsg;
+ unsigned int vlen;
+};
+struct trace_point_skb_copy_datagram_iovec {
+ __u64 pad_0;
+ void *skb;
+};
+
+#define BPF_PROBE_READ_VAR(value, ptr) bpf_probe_read(&value, sizeof(value), ptr)
+
+SEC("tracepoint/syscalls/sys_enter_write")
+int tracepoint_enter_write(struct trace_point_common_write *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.buf = ctx->buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_WRITE, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_write")
+int tracepoint_exit_write(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args && data_args->is_sock_event) {
+ ssize_t bytes_count = ctx->ret;
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_EGRESS, false, SOCKET_OPTS_TYPE_WRITE, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sendto")
+int tracepoint_enter_sendto(struct trace_point_enter_sendto *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ if (ctx->addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = ctx->addr;
+ connect_args.fd = ctx->fd;
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.buf = ctx->buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_SENDTO, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_sendto")
+int tracepoint_exit_sendto(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_SENDTO, CONNECTION_ROLE_TYPE_CLIENT);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_EGRESS, false, SOCKET_OPTS_TYPE_SENDTO, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_writev")
+int tracepoint_enter_writev(struct trace_point_common_writev *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.iovec = ctx->vec;
+ data_args.iovlen = ctx->count;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_WRITE, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_writev")
+int tracepoint_exit_writev(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args && data_args->is_sock_event) {
+ ssize_t bytes_count = ctx->ret;
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_EGRESS, true, SOCKET_OPTS_TYPE_WRITEV, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_sendmsg")
+int tracepoint_enter_sendmsg(struct trace_point_common_sendmsg *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+ struct user_msghdr* msghdr = ctx->msg;
+ if (msghdr == NULL) {
+ return 0;
+ }
+
+ struct sockaddr* addr = _(msghdr->msg_name);
+ if (addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = addr;
+ connect_args.fd = ctx->fd;
+ connect_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.iovec = _(msghdr->msg_iov);
+ data_args.iovlen = _(msghdr->msg_iovlen);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_SENDMSG, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_sendmsg")
+int tracepoint_exit_sendmsg(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_SENDMSG, CONNECTION_ROLE_TYPE_CLIENT);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_EGRESS, true, SOCKET_OPTS_TYPE_SENDMSG, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_sendmmsg")
+int tracepoint_enter_sendmmsg(struct trace_point_common_sendmmsg *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+ struct mmsghdr* mmsghdr = ctx->mmsg;
+ __u32 vlen = ctx->vlen;
+ if (mmsghdr == NULL || vlen <= 0) {
+ return 0;
+ }
+
+ struct sockaddr* addr = _(mmsghdr->msg_hdr.msg_name);
+ if (addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = addr;
+ connect_args.fd = ctx->fd;
+ connect_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ struct iovec *msg_iov = _(mmsghdr->msg_hdr.msg_iov);
+ data_args.iovec = msg_iov;
+ size_t msg_iovlen = _(mmsghdr->msg_hdr.msg_iovlen);
+ data_args.iovlen = msg_iovlen;
+ data_args.msg_len = (unsigned int*)(&mmsghdr->msg_hdr.msg_iovlen);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_SENDMSG, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_sendmmsg")
+int tracepoint_exit_sendmmsg(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_SENDMMSG, CONNECTION_ROLE_TYPE_CLIENT);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ __u32 bytes_count;
+ BPF_PROBE_READ_VAR(bytes_count, data_args->msg_len);
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_EGRESS, true, SOCKET_OPTS_TYPE_SENDMMSG, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_read")
+int tracepoint_enter_read(struct trace_point_common_write *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.buf = ctx->buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_READ, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_read")
+int tracepoint_exit_read(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args && data_args->is_sock_event) {
+ ssize_t bytes_count = ctx->ret;
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_READ, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_readv")
+int tracepoint_enter_readv(struct trace_point_common_readv *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.iovec = ctx->vec;
+ data_args.iovlen = ctx->count;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_READV, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_readv")
+int tracepoint_exit_readv(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args && data_args->is_sock_event) {
+ ssize_t bytes_count = ctx->ret;
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, true, SOCKET_OPTS_TYPE_READV, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("kprobe/recv")
+int sys_recv(struct pt_regs* ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ char* buf = (void *)SYSCALL_PARM_2(ctx);
+ struct sock_data_args_t data_args = {};
+ data_args.fd = SYSCALL_PARM_1(ctx);
+ data_args.buf = buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_RECV, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("kretprobe/recv")
+int sys_recv_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ ssize_t bytes_count = PT_REGS_RC(ctx);
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_RECV, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_recvfrom")
+int tracepoint_enter_recvfrom(struct trace_point_enter_recvfrom *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+
+ if (ctx->addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = ctx->addr;
+ connect_args.fd = ctx->fd;
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.buf = ctx->buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_RECVFROM, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_recvfrom")
+int tracepoint_exit_recvfrom(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_RECVFROM, CONNECTION_ROLE_TYPE_SERVER);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_RECVFROM, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_recvmsg")
+int tracepoint_enter_recvmsg(struct trace_point_common_recvmsg *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+ struct user_msghdr* msghdr = ctx->msg;
+ if (msghdr == NULL) {
+ return 0;
+ }
+
+ struct sockaddr* addr = _(msghdr->msg_name);
+ if (addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = addr;
+ connect_args.fd = ctx->fd;
+ connect_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ data_args.iovec = _(msghdr->msg_iov);
+ data_args.iovlen = _(msghdr->msg_iovlen);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_RECVMSG, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_recvmsg")
+int tracepoint_exit_recvmsg(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_RECVMSG, CONNECTION_ROLE_TYPE_SERVER);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, true, SOCKET_OPTS_TYPE_RECVMSG, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_enter_recvmmsg")
+int tracepoint_enter_recvmmsg(struct trace_point_common_recvmmsg *ctx) {
+ uint64_t id = bpf_get_current_pid_tgid();
+ if (tgid_should_trace(id >> 32) == false) {
+ return 0;
+ }
+ struct mmsghdr* mmsghdr = ctx->mmsg;
+ __u32 vlen = ctx->vlen;
+ if (mmsghdr == NULL || vlen <= 0) {
+ return 0;
+ }
+
+ struct sockaddr* addr = _(mmsghdr->msg_hdr.msg_name);
+ if (addr != NULL) {
+ struct connect_args_t connect_args = {};
+ connect_args.addr = addr;
+ connect_args.fd = ctx->fd;
+ connect_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&conecting_args, &id, &connect_args, 0);
+ }
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = ctx->fd;
+ struct iovec *msg_iov = _(mmsghdr->msg_hdr.msg_iov);
+ data_args.iovec = msg_iov;
+ size_t msg_iovlen = _(mmsghdr->msg_hdr.msg_iovlen);
+ data_args.iovlen = msg_iovlen;
+ data_args.msg_len = (unsigned int*)(&mmsghdr->msg_hdr.msg_iovlen);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ data_args.data_id = generate_socket_data_id(id, data_args.fd, SOCKET_OPTS_TYPE_RECVMMSG, false);
+ bpf_map_update_elem(&socket_data_args, &id, &data_args, 0);
+ return 0;
+}
+
+SEC("tracepoint/syscalls/sys_exit_recvmmsg")
+int tracepoint_exit_recvmmsg(struct trace_point_common_exit *ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ ssize_t bytes_count = ctx->ret;
+
+ // connection
+ struct connect_args_t *connect_args = bpf_map_lookup_elem(&conecting_args, &id);
+ if (connect_args && bytes_count > 0) {
+ submit_connection_when_not_exists(ctx, id, connect_args, SOCKET_OPTS_TYPE_RECVMMSG, CONNECTION_ROLE_TYPE_SERVER);
+ }
+ bpf_map_delete_elem(&conecting_args, &id);
+
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args) {
+ __u32 bytes_count;
+ BPF_PROBE_READ_VAR(bytes_count, data_args->msg_len);
+ process_write_data(ctx, id, data_args, bytes_count, SOCK_DATA_DIRECTION_INGRESS, true, SOCKET_OPTS_TYPE_RECVMMSG, false);
+ }
+
+ bpf_map_delete_elem(&socket_data_args, &id);
+ return 0;
+}
+
+SEC("tracepoint/skb/skb_copy_datagram_iovec")
+int tracepoint_skb_copy_datagram_iovec(struct trace_point_skb_copy_datagram_iovec* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args == NULL) {
+ return 0;
+ }
+
+ struct sk_buff *buff = ctx->skb;
+ struct skb_receive_detail *detail = bpf_map_lookup_elem(&sk_buff_receive_detail_map, &buff);
+ if (detail == NULL) {
+ return 0;
+ }
+ bpf_map_delete_elem(&sk_buff_receive_detail_map, &buff);
+
+ // l4
+ data_args->enter_l4_time = detail->enter_tcp_rcv_time;
+ data_args->exit_l4_time = detail->exit_tcp_rcv_time;
+
+ // l3
+ if (detail->exit_ip_rcv_time > 0 && detail->enter_ip_rcv_time > 0) {
+ data_args->l3_duration += detail->exit_ip_rcv_time - detail->enter_ip_rcv_time;
+ }
+ if (detail->ip_rcv_finish_time > 0 && detail->enter_ip_rcv_time > 0) {
+ data_args->l3_rcv_duration += detail->ip_rcv_finish_time - detail->enter_ip_rcv_time;
+ }
+ if (detail->ip_local_finish_time > 0 && detail->ip_local_time > 0) {
+ data_args->l3_local_duration += detail->ip_local_finish_time - detail->ip_local_time;
+ }
+ data_args->total_net_filter_count += detail->total_nf_count;
+ data_args->total_net_filter_time += detail->total_nf_time;
+
+ // l2
+ data_args->ifindex = detail->ifindex;
+ data_args->package_count++;
+ data_args->total_package_size += _(buff->len);
+ if (detail->netif_receive_time > 0 && detail->ip_local_time > 0) {
+ data_args->total_package_to_queue_time += detail->ip_local_time - detail->netif_receive_time;
+ }
+ if (detail->ip_local_time > 0) {
+ data_args->total_package_receive_from_queue_time += bpf_ktime_get_ns() - detail->ip_local_time;
+ }
+
+ struct sock *sock = _(buff->sk);
+ if (sock != NULL) {
+ data_args->sk_role = get_sock_role(data_args->sk_role, sock);
+ }
+
+ return 0;
+}
+
+SEC("kprobe/security_socket_sendmsg")
+int security_socket_sendmsg(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ data_args->is_sock_event = true;
+ }
+ return 0;
+}
+
+SEC("kprobe/security_socket_recvmsg")
+int security_socket_recvmsg(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *data_args = bpf_map_lookup_elem(&socket_data_args, &id);
+ if (data_args != NULL) {
+ data_args->is_sock_event = true;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/syscalls/transfer.h b/bpf/accesslog/syscalls/transfer.h
new file mode 100644
index 0000000..2c72d51
--- /dev/null
+++ b/bpf/accesslog/syscalls/transfer.h
@@ -0,0 +1,352 @@
+// 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 "api.h"
+#include "socket_opts.h"
+#include "socket_reader.h"
+#include "protocol_analyzer.h"
+#include "../common/connection.h"
+#include "../common/data_args.h"
+
+#define SOCKET_UPLOAD_CHUNK_LIMIT 12
+
+// openssl read or write
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, struct sock_data_args_t);
+} openssl_sock_data_args SEC(".maps");
+
+struct socket_detail_t {
+ // basic information
+ __u64 connection_id;
+ __u64 random_id;
+ __u64 data_id;
+
+ // socket data operation times
+ __u64 start_nacs;
+ __u64 end_nacs;
+
+ // l2-l4
+ __u32 l4_duration;
+ __u32 l3_duration;
+ __u32 l3_local_duration;
+ __u32 l3_output_duration;
+ __u32 l3_resolve_mac_duration;
+ __u32 l3_net_filter_duration;
+ __u32 l2_duration;
+ __u32 l2_ready_send_duration;
+ __u32 l2_send_duration;
+ __u32 l2_package_to_queue_time;
+ __u32 l3_total_recv_time;
+ __u32 ifindex;
+ __u64 l4_package_rcv_from_queue_time;
+ __u64 l4_total_package_size;
+ __u8 l2_enter_queue_count;
+ __u8 l4_package_count;
+ __u8 l4_retransmit_package_count;
+ __u8 l3_resolve_mac_count;
+ __u8 l3_net_filter_count;
+ __u8 op_func_name;
+ __u8 data_protocol;
+ __u8 ssl;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, __u32);
+ __type(value, struct socket_detail_t);
+ __uint(max_entries, 1);
+} socket_detail_event_per_cpu_map SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} socket_detail_data_queue SEC(".maps");
+
+struct socket_data_upload_event {
+ __u8 protocol;
+ __u8 have_reduce_after_chunk;
+ __u8 direction;
+ __u8 finished;
+ __u16 sequence;
+ __u16 data_len;
+ __u64 start_time;
+ __u64 end_time;
+ __u64 conid;
+ __u64 randomid;
+ __u64 data_id;
+ __u64 total_size;
+ char buffer[MAX_TRANSMIT_SOCKET_READ_LENGTH + 1];
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, __u32);
+ __type(value, struct socket_data_upload_event);
+ __uint(max_entries, 1);
+} socket_data_upload_event_per_cpu_map SEC(".maps");
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+} socket_data_upload_event_queue SEC(".maps");
+
+struct socket_data_sequence_t {
+ __u64 data_id;
+ __u16 sequence;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_LRU_HASH);
+ __uint(max_entries, 1000);
+ __type(key, __u64);
+ __type(value, struct socket_data_sequence_t);
+} socket_data_sequence_generator SEC(".maps");
+static __inline __u16 generate_socket_sequence(__u64 conid, __u64 data_id) {
+ struct socket_data_sequence_t *seq = bpf_map_lookup_elem(&socket_data_sequence_generator, &conid);
+ if (seq == NULL) {
+ struct socket_data_sequence_t data = {};
+ data.data_id = data_id;
+ data.sequence = 0;
+ bpf_map_update_elem(&socket_data_sequence_generator, &conid, &data, BPF_NOEXIST);
+ return 0;
+ }
+ if (seq->data_id != data_id) {
+ seq->data_id = data_id;
+ seq->sequence = 0;
+ } else {
+ seq->sequence++;
+ }
+ return seq->sequence;
+}
+
+static __inline void upload_socket_detail(void *ctx, __u64 conid, struct active_connection_t *connection, __u8 func_name, struct sock_data_args_t *data_args, bool ssl, __u64 end_nacs) {
+ // only send the original socket syscall(not ssl)
+ if (ssl == true) {
+ return;
+ }
+ __u32 kZero = 0;
+ struct socket_detail_t *detail = bpf_map_lookup_elem(&socket_detail_event_per_cpu_map, &kZero);
+ if (detail == NULL) {
+ return;
+ }
+
+ detail->connection_id = conid;
+ detail->random_id = connection->random_id;
+ detail->data_id = data_args->data_id;
+
+ detail->start_nacs = data_args->start_nacs;
+ detail->end_nacs = end_nacs;
+
+ detail->l4_duration = data_args->exit_l4_time - data_args->enter_l4_time;
+ detail->l3_duration = data_args->l3_duration;
+ detail->l3_local_duration = data_args->l3_local_duration;
+ detail->l3_output_duration = data_args->l3_output_duration;
+ detail->l3_resolve_mac_duration = data_args->total_resolve_mac_time;
+ detail->l3_net_filter_duration = data_args->total_net_filter_time;
+ detail->l2_duration = data_args->l2_duration;
+ detail->l2_ready_send_duration = data_args->l2_ready_send_duration;
+ detail->l2_send_duration = data_args->l2_send_duration;
+ detail->ifindex = data_args->ifindex;
+ detail->l4_total_package_size = data_args->total_package_size;
+ detail->l4_package_count = data_args->package_count;
+ detail->l4_retransmit_package_count = data_args->retransmit_package_count;
+ detail->l3_resolve_mac_count = data_args->total_resolve_mac_count;
+ detail->l3_net_filter_count = data_args->total_net_filter_count;
+ detail->op_func_name = func_name;
+ detail->data_protocol = connection->protocol;
+ detail->ssl = connection->ssl;
+ detail->l2_package_to_queue_time = data_args->total_package_to_queue_time;
+ detail->l3_total_recv_time = data_args->l3_rcv_duration;
+ detail->l2_enter_queue_count = data_args->l2_enter_queue_count;
+ detail->l4_package_rcv_from_queue_time = data_args->total_package_receive_from_queue_time;
+
+ // loss package detail
+
+ bpf_perf_event_output(ctx, &socket_detail_data_queue, BPF_F_CURRENT_CPU, detail, sizeof(*detail));
+}
+
+static __always_inline void __upload_socket_data_with_buffer(void *ctx, __u8 index, char* buf, size_t size, __u32 is_finished, __u8 have_reduce_after_chunk, struct socket_data_upload_event *event) {
+ event->sequence = index;
+ event->data_len = size;
+ event->finished = is_finished;
+ event->have_reduce_after_chunk = have_reduce_after_chunk;
+ if (size <= 0) {
+ return;
+ }
+ asm volatile("%[size] &= 0x7ff;\n" ::[size] "+r"(size) :);
+ bpf_probe_read(&event->buffer, size & 0x7ff, buf);
+
+ bpf_perf_event_output(ctx, &socket_data_upload_event_queue, BPF_F_CURRENT_CPU, event, sizeof(*event));
+}
+
+static __always_inline void upload_socket_data_buf(void *ctx, char* buf, ssize_t size, struct socket_data_upload_event *event, __u8 force_unfinished) {
+ ssize_t already_send = 0;
+#pragma unroll
+ for (__u8 index = 0; index < SOCKET_UPLOAD_CHUNK_LIMIT; index++) {
+ // calculate bytes need to send
+ ssize_t remaining = size - already_send;
+ size_t need_send_in_chunk = 0;
+ __u8 have_reduce_after_chunk = 0;
+ if (remaining > MAX_TRANSMIT_SOCKET_READ_LENGTH) {
+ need_send_in_chunk = MAX_TRANSMIT_SOCKET_READ_LENGTH;
+ have_reduce_after_chunk = 1;
+ } else {
+ need_send_in_chunk = remaining;
+ }
+
+ __u32 is_finished = (need_send_in_chunk + already_send) >= size || index == (SOCKET_UPLOAD_CHUNK_LIMIT - 1) ? true : false;
+ __u8 sequence = index;
+ if (force_unfinished == 1 && need_send_in_chunk > 0) {
+ is_finished = 0;
+ sequence = generate_socket_sequence(event->conid, event->data_id);
+ }
+ __upload_socket_data_with_buffer(ctx, sequence, buf + already_send, need_send_in_chunk, is_finished, have_reduce_after_chunk, event);
+ already_send += need_send_in_chunk;
+
+ }
+}
+
+#define UPLOAD_PER_SOCKET_DATA_IOV() \
+if (iov_index < iovlen) { \
+ struct iovec cur_iov; \
+ bpf_probe_read(&cur_iov, sizeof(cur_iov), &iov[iov_index]); \
+ ssize_t remaining = size - already_send; \
+ size_t need_send_in_chunk = remaining - cur_iov_sended; \
+ __u8 have_reduce_after_chunk = 0; \
+ if (cur_iov_sended + need_send_in_chunk > cur_iov.iov_len) { \
+ need_send_in_chunk = cur_iov.iov_len - cur_iov_sended; \
+ if (need_send_in_chunk > MAX_TRANSMIT_SOCKET_READ_LENGTH) { \
+ need_send_in_chunk = MAX_TRANSMIT_SOCKET_READ_LENGTH; \
+ have_reduce_after_chunk = 1; \
+ } else { \
+ iov_index++; \
+ cur_iov_sended = 0; \
+ } \
+ } else if (need_send_in_chunk > MAX_TRANSMIT_SOCKET_READ_LENGTH) { \
+ need_send_in_chunk = MAX_TRANSMIT_SOCKET_READ_LENGTH; \
+ have_reduce_after_chunk = 1; \
+ } \
+ __u32 is_finished = (need_send_in_chunk + already_send) >= size || loop_count == (SOCKET_UPLOAD_CHUNK_LIMIT - 1) ? true : false; \
+ __upload_socket_data_with_buffer(ctx, loop_count, cur_iov.iov_base + cur_iov_sended, need_send_in_chunk, is_finished, have_reduce_after_chunk, event); \
+ already_send += need_send_in_chunk; \
+ loop_count++; \
+}
+
+static __always_inline void upload_socket_data_iov(void *ctx, struct iovec* iov, const size_t iovlen, ssize_t size, struct socket_data_upload_event *event) {
+ ssize_t already_send = 0;
+ ssize_t cur_iov_sended = 0;
+ __u8 iov_index = 0;
+ __u8 loop_count = 0;
+
+ // each count is same with SOCKET_UPLOAD_CHUNK_LIMIT
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+ UPLOAD_PER_SOCKET_DATA_IOV();
+}
+
+static __inline void upload_socket_data(void *ctx, __u64 start_time, __u64 end_time, __u64 conid, struct active_connection_t *connection, struct sock_data_args_t *args, ssize_t bytes_count, __u32 existing_msg_type, __u32 data_direction, bool ssl) {
+ // must have protocol and ssl must same(plain)
+ // if the connection data is needs to skip upload, then skip
+ if (connection->protocol == CONNECTION_PROTOCOL_UNKNOWN || connection->ssl != ssl || connection->skip_data_upload == 1) {
+ return;
+ }
+ // generate event
+ __u32 kZero = 0;
+ struct socket_data_upload_event *event = bpf_map_lookup_elem(&socket_data_upload_event_per_cpu_map, &kZero);
+ if (event == NULL) {
+ return;
+ }
+
+ // basic data
+ event->start_time = start_time;
+ event->end_time = end_time;
+ event->protocol = connection->protocol;
+ event->direction = data_direction;
+ event->conid = conid;
+ event->randomid = connection->random_id;
+ event->total_size = bytes_count;
+ event->data_id = args->data_id;
+
+ if (args->buf != NULL) {
+ upload_socket_data_buf(ctx, args->buf, bytes_count, event, args->ssl_buffer_force_unfinished);
+ } else if (args->iovec != NULL) {
+ upload_socket_data_iov(ctx, args->iovec, args->iovlen, bytes_count, event);
+ }
+}
+
+static __always_inline void process_write_data(void *ctx, __u64 id, struct sock_data_args_t *args, ssize_t bytes_count,
+ __u32 data_direction, const bool vecs, __u8 func_name, bool ssl) {
+ __u64 curr_nacs = bpf_ktime_get_ns();
+ __u32 tgid = (__u32)(id >> 32);
+
+ if (vecs && args->iovlen <= 0) {
+ return;
+ }
+ if (args->fd < 0) {
+ return;
+ }
+ if (bytes_count <= 0) {
+ return;
+ }
+
+ // get current connection
+ struct active_connection_t *conn = get_or_create_active_conn(ctx, tgid, args->fd, func_name, args->sk_role);
+ if (conn == NULL) {
+ return;
+ }
+ // only trace ipv4, v6, or unknown
+ if (family_should_trace(conn->socket_family) == false) {
+ return;
+ }
+ // process the ssl request if the fd not found
+ struct sock_data_args_t *ssl_data_args = bpf_map_lookup_elem(&openssl_sock_data_args, &id);
+ if (ssl_data_args != NULL && ssl_data_args->fd == 0) {
+ ssl_data_args->fd = args->fd;
+ conn->ssl = true;
+ }
+
+ // if the protocol or role is unknown in the connection and the current data content is plaintext
+ // then try to use protocol analyzer to analyze request or response and protocol type
+ __u32 msg_type = 0;
+ if ((conn->role == CONNECTION_ROLE_TYPE_UNKNOWN || conn->protocol == 0) && conn->ssl == ssl) {
+ struct socket_buffer_reader_t *buf_reader = read_socket_data(args->buf, args->iovec, bytes_count);
+ if (buf_reader != NULL) {
+ msg_type = analyze_protocol(buf_reader->buffer, buf_reader->data_len, &conn->protocol);
+ // if send request data to remote address or receive response data from remote address
+ // then, recognized current connection is client
+ if ((msg_type == CONNECTION_MESSAGE_TYPE_REQUEST && data_direction == SOCK_DATA_DIRECTION_EGRESS) ||
+ (msg_type == CONNECTION_MESSAGE_TYPE_RESPONSE && data_direction == SOCK_DATA_DIRECTION_INGRESS)) {
+ conn->role = CONNECTION_ROLE_TYPE_CLIENT;
+
+ // if send response data to remote address or receive request data from remote address
+ // then, recognized current connection is server
+ } else if ((msg_type == CONNECTION_MESSAGE_TYPE_RESPONSE && data_direction == SOCK_DATA_DIRECTION_EGRESS) ||
+ (msg_type == CONNECTION_MESSAGE_TYPE_REQUEST && data_direction == SOCK_DATA_DIRECTION_INGRESS)) {
+ conn->role = CONNECTION_ROLE_TYPE_SERVER;
+ }
+ }
+ }
+
+ __u64 conid = gen_tgid_fd(tgid, args->fd);
+ // upload the socket detail
+ upload_socket_detail(ctx, conid, conn, func_name, args, ssl, curr_nacs);
+
+ // upload the socket data if need
+ upload_socket_data(ctx, args->start_nacs, curr_nacs, conid, conn, args, bytes_count, msg_type, data_direction, ssl);
+}
\ No newline at end of file
diff --git a/bpf/accesslog/tls/go_tls.c b/bpf/accesslog/tls/go_tls.c
new file mode 100644
index 0000000..311ec73
--- /dev/null
+++ b/bpf/accesslog/tls/go_tls.c
@@ -0,0 +1,195 @@
+// 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 "tls.h"
+#include "go_tls.h"
+#include "goid.h"
+
+SEC("uprobe/go_tls_write")
+int go_tls_write(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ __u64 goid = get_goid(id);
+ if (goid == 0) {
+ return 0;
+ }
+
+ struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+ if (symaddrs == NULL) {
+ return 0;
+ }
+
+ const void* sp = (const void*)PT_REGS_SP(ctx);
+ __u64* regs = go_regabi_regs(ctx);
+ if (regs == NULL) {
+ return 0;
+ }
+
+ struct go_tls_tgid_goid_t tgid_goid = {};
+ tgid_goid.tgid = tgid;
+ tgid_goid.goid = goid;
+
+ struct go_tls_connection_args_t data_args = {};
+ assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->write_connection_loc, sp, regs);
+ assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), symaddrs->write_buffer_loc, sp, regs);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, &data_args, 0);
+ return 0;
+}
+
+SEC("uretprobe/go_tls_write")
+int go_tls_write_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ __u64 goid = get_goid(id);
+ if (goid == 0) {
+ return 0;
+ }
+
+ struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+ if (symaddrs == NULL) {
+ return 0;
+ }
+
+ const void* sp = (const void*)PT_REGS_SP(ctx);
+ __u64* regs = go_regabi_regs(ctx);
+ if (regs == NULL) {
+ return 0;
+ }
+
+ int64_t retval0 = 0;
+ assign_go_tls_arg(&retval0, sizeof(retval0), symaddrs->write_ret0_loc, sp, regs);
+ struct go_interface retval1 = {};
+ assign_go_tls_arg(&retval1, sizeof(retval1), symaddrs->write_ret1_loc, sp, regs);
+ if (retval1.ptr != 0) {
+ return 0;
+ }
+
+ struct go_tls_tgid_goid_t tgid_goid = {};
+ tgid_goid.tgid = tgid;
+ tgid_goid.goid = goid;
+
+ struct go_tls_connection_args_t *args = bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
+ if (args) {
+ struct go_interface conn_intf = {};
+ conn_intf.type = 1;
+ conn_intf.ptr = args->connection_ptr;
+ int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
+
+ set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_WRITE);
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = fd;
+ data_args.buf = args->buffer_ptr;
+ data_args.start_nacs = args->start_nacs;
+ data_args.data_id = get_socket_data_id(6, id, fd);
+
+ process_write_data(ctx, id, &data_args, retval0, SOCK_DATA_DIRECTION_EGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+ }
+ bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
+ return 0;
+}
+
+
+SEC("uprobe/go_tls_read")
+int go_tls_read(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ __u64 goid = get_goid(id);
+ if (goid == 0) {
+ return 0;
+ }
+
+ struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+ if (symaddrs == NULL) {
+ return 0;
+ }
+
+ const void* sp = (const void*)PT_REGS_SP(ctx);
+ __u64* regs = go_regabi_regs(ctx);
+ if (regs == NULL) {
+ return 0;
+ }
+
+ struct go_tls_tgid_goid_t tgid_goid = {};
+ tgid_goid.tgid = tgid;
+ tgid_goid.goid = goid;
+
+ struct go_tls_connection_args_t data_args = {};
+ assign_go_tls_arg(&data_args.connection_ptr, sizeof(data_args.connection_ptr), symaddrs->read_connection_loc, sp, regs);
+ assign_go_tls_arg(&data_args.buffer_ptr, sizeof(data_args.buffer_ptr), symaddrs->read_buffer_loc, sp, regs);
+ data_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&go_tls_active_connection_args, &tgid_goid, &data_args, 0);
+ return 0;
+}
+
+SEC("uretprobe/go_tls_read")
+int go_tls_read_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ __u64 goid = get_goid(id);
+ if (goid == 0) {
+ return 0;
+ }
+
+ struct go_tls_args_symaddr_t* symaddrs = get_go_tls_args_symaddr(tgid);
+ if (symaddrs == NULL) {
+ return 0;
+ }
+
+ const void* sp = (const void*)PT_REGS_SP(ctx);
+ __u64* regs = go_regabi_regs(ctx);
+ if (regs == NULL) {
+ return 0;
+ }
+
+ int64_t retval0 = 0;
+ assign_go_tls_arg(&retval0, sizeof(retval0), symaddrs->read_ret0_loc, sp, regs);
+ struct go_interface retval1 = {};
+ assign_go_tls_arg(&retval1, sizeof(retval1), symaddrs->read_ret1_loc, sp, regs);
+ if (retval1.ptr != 0) {
+ return 0;
+ }
+
+ struct go_tls_tgid_goid_t tgid_goid = {};
+ tgid_goid.tgid = tgid;
+ tgid_goid.goid = goid;
+
+ struct go_tls_connection_args_t *args = bpf_map_lookup_elem(&go_tls_active_connection_args, &tgid_goid);
+ if (args) {
+ struct go_interface conn_intf = {};
+ conn_intf.type = 1;
+ conn_intf.ptr = args->connection_ptr;
+ int fd = get_fd_from_go_tls_conn(conn_intf, symaddrs);
+
+ set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_GOTLS_READ);
+
+ struct sock_data_args_t data_args = {};
+ data_args.fd = fd;
+ data_args.buf = args->buffer_ptr;
+ data_args.start_nacs = args->start_nacs;
+ data_args.data_id = get_socket_data_id(8, id, fd);
+
+ process_write_data(ctx, id, &data_args, retval0, SOCK_DATA_DIRECTION_INGRESS, false, SOCKET_OPTS_TYPE_GOTLS_WRITE, true);
+ }
+ bpf_map_delete_elem(&go_tls_active_connection_args, &tgid_goid);
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/tls/go_tls.h b/bpf/accesslog/tls/go_tls.h
new file mode 100644
index 0000000..1057ef9
--- /dev/null
+++ b/bpf/accesslog/tls/go_tls.h
@@ -0,0 +1,49 @@
+// 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 "symbol_offsets.h"
+
+struct go_tls_tgid_goid_t {
+ __u64 tgid;
+ __u64 goid;
+};
+struct go_tls_connection_args_t {
+ void* connection_ptr;
+ char* buffer_ptr;
+ __u64 start_nacs;
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, struct go_tls_tgid_goid_t);
+ __type(value, struct go_tls_connection_args_t);
+} go_tls_active_connection_args SEC(".maps");
+
+static __always_inline int get_fd_from_go_tls_conn(struct go_interface conn, struct go_tls_args_symaddr_t* symaddr) {
+ // read connection
+ bpf_probe_read(&conn, sizeof(conn), conn.ptr + symaddr->tls_conn_offset);
+
+ if (conn.type != symaddr->tcp_conn_offset) {
+ return 0;
+ }
+
+ void* fd_ptr;
+ bpf_probe_read(&fd_ptr, sizeof(fd_ptr), conn.ptr);
+ __u64 sysfd;
+ bpf_probe_read(&sysfd, sizeof(sysfd), fd_ptr + symaddr->fd_sys_offset);
+ return sysfd;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/tls/node_tls.c b/bpf/accesslog/tls/node_tls.c
new file mode 100644
index 0000000..6f293d2
--- /dev/null
+++ b/bpf/accesslog/tls/node_tls.c
@@ -0,0 +1,50 @@
+// 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 "node_tls.h"
+
+SEC("uprobe/node_tls_wrap")
+int node_tls_wrap(struct pt_regs* ctx) {
+ void* tls_wrap = (void*)PT_REGS_PARM1(ctx);
+ __u64 id = bpf_get_current_pid_tgid();
+ bpf_map_update_elem(&node_tls_wrap_construct_args_map, &id, &tls_wrap, 0);
+ return 0;
+}
+
+SEC("uretprobe/node_tls_wrap")
+int node_tls_wrap_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ bpf_map_delete_elem(&node_tls_wrap_construct_args_map, &id);
+ return 0;
+}
+
+SEC("uretprobe/ssl_new")
+int node_tls_ret_ssl(struct pt_regs* ctx) {
+ // get ssl data
+ void* ssl = (void*)PT_REGS_RC(ctx);
+ if (ssl == NULL) {
+ return 0;
+ }
+ // get node tls_wrap
+ __u64 id = bpf_get_current_pid_tgid();
+ struct ssl_wrap **wrap = bpf_map_lookup_elem(&node_tls_wrap_construct_args_map, &id);
+ if (wrap == NULL) {
+ return 0;
+ }
+ bpf_map_update_elem(&node_tls_ssl_wrap_mapping, &ssl, wrap, 0);
+ return 0;
+}
\ No newline at end of file
diff --git a/bpf/accesslog/tls/node_tls.h b/bpf/accesslog/tls/node_tls.h
new file mode 100644
index 0000000..b51472d
--- /dev/null
+++ b/bpf/accesslog/tls/node_tls.h
@@ -0,0 +1,79 @@
+// 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.
+
+#pragma once
+
+struct node_tls_symaddr_t {
+ __u32 tlsWrapStreamListenerOffset;
+ __u32 streamListenerStreamOffset;
+ __u32 streamBaseStreamResourceOffset;
+ __u32 libuvStreamWrapStreamBaseOffset;
+ __u32 libuvStreamWrapStreamOffset;
+ __u32 uvStreamSIOWatcherOffset;
+ __u32 uvIOSFDOffset;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u64);
+ __type(value, void*);
+} node_tls_wrap_construct_args_map SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, void*);
+ __type(value, void*);
+} node_tls_ssl_wrap_mapping SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_HASH);
+ __uint(max_entries, 10000);
+ __type(key, __u32);
+ __type(value, struct node_tls_symaddr_t);
+} node_tls_symaddr_map SEC(".maps");
+static __inline int get_node_tls_wrap_fd(__u32 tgid, void *tlsWrap) {
+ struct node_tls_symaddr_t *addr = bpf_map_lookup_elem(&node_tls_symaddr_map, &tgid);
+ if (addr == NULL) {
+ return -1;
+ }
+
+ void *stream = NULL;
+ bpf_probe_read(&stream, sizeof(stream), tlsWrap + addr->tlsWrapStreamListenerOffset + addr->streamListenerStreamOffset);
+ if (stream == NULL) {
+ return -1;
+ }
+
+ void *uv_stream = NULL;
+ bpf_probe_read(&uv_stream, sizeof(uv_stream), stream - addr->streamBaseStreamResourceOffset - addr->libuvStreamWrapStreamBaseOffset +
+ addr->libuvStreamWrapStreamOffset);
+ if (uv_stream == NULL) {
+ return -1;
+ }
+
+ __u64 fd;
+ bpf_probe_read(&fd, sizeof(fd), uv_stream + addr->uvStreamSIOWatcherOffset + addr->uvIOSFDOffset);
+ return fd;
+}
+static __inline int get_node_tls_fd(__u32 tgid, void *ssl) {
+ void **tlsWrap = bpf_map_lookup_elem(&node_tls_ssl_wrap_mapping, &ssl);
+ if (tlsWrap == NULL) {
+ return -1;
+ }
+ return get_node_tls_wrap_fd(tgid, *tlsWrap);
+}
\ No newline at end of file
diff --git a/bpf/accesslog/tls/openssl.c b/bpf/accesslog/tls/openssl.c
new file mode 100644
index 0000000..5b2c974
--- /dev/null
+++ b/bpf/accesslog/tls/openssl.c
@@ -0,0 +1,132 @@
+// 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 "symbol_offsets.h"
+#include "openssl.h"
+#include "node_tls.h"
+
+static __inline void process_openssl_data(struct pt_regs* ctx, __u64 id, __u32 data_direction, struct sock_data_args_t* args, __u32 func_name) {
+ int bytes_count = PT_REGS_RC(ctx);
+ if (data_direction == SOCK_DATA_DIRECTION_INGRESS) {
+ // not reading finish, needs to keep reading
+ // NOTE: if the connection is server side role, and receive a unfinished message,
+ // the message type and protocol may could not be recognized.
+ // because some SSL framework only read one byte on each SSL_read method call,
+ // unless we save the buffer data, then process the SSL data.
+ size_t excepted_size = args->excepted_size;
+ if (bytes_count > 0 && bytes_count >= excepted_size) {
+ args->ssl_buffer_force_unfinished = 1;
+ }
+ }
+ process_write_data(ctx, id, args, bytes_count, data_direction, false, func_name, true);
+}
+
+static int get_fd_symaddr(__u32 tgid, bool read, void* ssl) {
+ struct openssl_symaddr* addr = get_openssl_symaddr(tgid);
+ if (addr == NULL) {
+ return -1;
+ }
+ __u32 bio_offset = read ? addr->bio_read_offset : addr->bio_write_offset;
+ __u32 fd_offset = addr->fd_offset;
+
+ void *bio = NULL;
+ bpf_probe_read(&bio, sizeof(bio), ssl + bio_offset);
+ __u32 fd;
+ bpf_probe_read(&fd, sizeof(fd), bio + fd_offset);
+
+ return fd;
+}
+
+static int get_fd(uint32_t tgid, bool read, void* ssl) {
+ int fd = 0;
+
+ fd = get_fd_symaddr(tgid, read, ssl);
+ if (fd > 2) {
+ return fd;
+ }
+
+ fd = get_node_tls_fd(tgid, ssl);
+ if (fd > 0) {
+ return fd;
+ }
+
+ return 0;
+}
+
+SEC("uprobe/ssl_write")
+int openssl_write(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ void* ssl = (void*)PT_REGS_PARM1(ctx);
+ __u32 fd = get_fd(tgid, false, ssl);
+
+ char* buf = (char*)PT_REGS_PARM2(ctx);
+ struct sock_data_args_t data_args = {};
+ data_args.fd = fd;
+ data_args.buf = buf;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&openssl_sock_data_args, &id, &data_args, 0);
+
+ set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_SSL_WRITE);
+ return 0;
+}
+
+SEC("uretprobe/ssl_write")
+int openssl_write_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *args = bpf_map_lookup_elem(&openssl_sock_data_args, &id);
+ if (args && args->fd > 0) {
+ args->data_id = get_socket_data_id(2, id, args->fd);
+ process_openssl_data(ctx, id, SOCK_DATA_DIRECTION_EGRESS, args, SOCKET_OPTS_TYPE_SSL_WRITE);
+ }
+ bpf_map_delete_elem(&openssl_sock_data_args, &id);
+ return 0;
+}
+
+SEC("uprobe/ssl_read")
+int openssl_read(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ __u32 tgid = id >> 32;
+
+ void* ssl = (void*)PT_REGS_PARM1(ctx);
+ __u32 fd = get_fd(tgid, true, ssl);
+
+ char* buf = (char*)PT_REGS_PARM2(ctx);
+ size_t excepted_size = PT_REGS_PARM3(ctx);
+ struct sock_data_args_t data_args = {};
+ data_args.fd = fd;
+ data_args.buf = buf;
+ data_args.excepted_size = excepted_size;
+ data_args.start_nacs = bpf_ktime_get_ns();
+ bpf_map_update_elem(&openssl_sock_data_args, &id, &data_args, 0);
+
+ set_conn_as_ssl(ctx, tgid, fd, SOCKET_OPTS_TYPE_SSL_WRITE);
+ return 0;
+}
+
+SEC("uretprobe/ssl_read")
+int openssl_read_ret(struct pt_regs* ctx) {
+ __u64 id = bpf_get_current_pid_tgid();
+ struct sock_data_args_t *args = bpf_map_lookup_elem(&openssl_sock_data_args, &id);
+ if (args && args->fd > 0) {
+ args->data_id = get_socket_data_id(4, id, args->fd);
+ process_openssl_data(ctx, id, SOCK_DATA_DIRECTION_INGRESS, args, SOCKET_OPTS_TYPE_SSL_READ);
+ }
+ bpf_map_delete_elem(&openssl_sock_data_args, &id);
+ return 0;
+}
\ No newline at end of file
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/bpf/accesslog/tls/openssl.h
similarity index 88%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to bpf/accesslog/tls/openssl.h
index 555705c..3fa197d 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/bpf/accesslog/tls/openssl.h
@@ -15,11 +15,3 @@
// specific language governing permissions and limitations
// under the License.
-package enums
-
-type ParseResult int
-
-const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
-)
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/bpf/accesslog/tls/tls.h
similarity index 68%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to bpf/accesslog/tls/tls.h
index 555705c..52a2c34 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/bpf/accesslog/tls/tls.h
@@ -15,11 +15,15 @@
// specific language governing permissions and limitations
// under the License.
-package enums
+#pragma once
-type ParseResult int
+#include "../common/connection.h"
+#include "socket_opts.h"
-const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
-)
+static __always_inline void set_conn_as_ssl(struct pt_regs* ctx, __u32 tgid, __u32 fd, __u32 func_name) {
+ struct active_connection_t* conn = get_or_create_active_conn(ctx, tgid, fd, func_name, CONNECTION_ROLE_TYPE_UNKNOWN);
+ if (conn == NULL) {
+ return;
+ }
+ conn->ssl = true;
+};
diff --git a/bpf/include/list.h b/bpf/include/list.h
new file mode 100644
index 0000000..9658687
--- /dev/null
+++ b/bpf/include/list.h
@@ -0,0 +1,102 @@
+// 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.
+
+#pragma once
+
+#include "api.h"
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ __u8 i = 0; \
+ for (pos = list_entry(_((head)->next), typeof(*pos), member), \
+ n = list_entry(_(pos->member.next), typeof(*pos), member); \
+ &pos->member != (head) && i < 255; \
+ pos = n, n = list_entry(_(n->member.next), typeof(*n), member), i++)
+
+// use for for-each the list without for loop(lower linux kernel)
+// use list_for_each_entry_init at first, and use list_for_each_entry_data multiples for the loop
+#define list_for_each_entry_init() \
+ bool list_is_first = true; \
+ bool list_should_enter = false;
+
+#define list_for_each_entry_data(pos, n, head, member) \
+ if (list_is_first) { \
+ list_should_enter = true; \
+ list_is_first = false; \
+ pos = list_entry(_((head)->next), typeof(*pos), member); \
+ n = list_entry(_(pos->member.next), typeof(*pos), member); \
+ } else if (list_should_enter) { \
+ pos = n; \
+ n = list_entry(_(n->member.next), typeof(*n), member); \
+ list_should_enter = &pos->member != (head); \
+ } \
+ if (list_should_enter)
+
+// Customized BPF List implementation
+struct bpf_list_head {
+ void *data;
+ struct bpf_list_head *next;
+};
+
+static inline struct bpf_list_head init_bpf_list_head() {
+ struct bpf_list_head head = {};
+ head.data = NULL;
+ head.next = NULL;
+ return head;
+}
+
+static inline struct bpf_list_head append_bpf_list_head(struct bpf_list_head* head, void *data) {
+ struct bpf_list_head new_head = init_bpf_list_head();
+ new_head.data = data;
+ new_head.next = head;
+ return new_head;
+}
+
+static inline int bpf_list_empty(struct bpf_list_head *head) {
+ return head->next == NULL;
+}
+
+#define bpf_list_for_each_init() \
+ bool bpf_list_is_first = true; \
+ struct bpf_list_head *current_node = NULL;
+
+#define bpf_list_for_each_foreach(pos, head) \
+ if (bpf_list_is_first) { \
+ current_node = head; \
+ pos = head->data;\
+ } else if (current_node != NULL) { \
+ current_node = current_node->next; \
+ if (current_node != NULL) {\
+ pos = current_node->data; \
+ }\
+ } \
+ if (current_node != NULL && current_node->next != NULL)
\ No newline at end of file
diff --git a/bpf/include/protocol_analyzer.h b/bpf/include/protocol_analyzer.h
index 737e557..7efc85e 100644
--- a/bpf/include/protocol_analyzer.h
+++ b/bpf/include/protocol_analyzer.h
@@ -71,6 +71,18 @@ static __inline __u32 infer_http1_message(const char* buf, size_t count) {
return CONNECTION_MESSAGE_TYPE_UNKNOWN;
}
+static bool is_http2_magic(const char *buf_src, size_t count)
+{
+ static const char magic[] = "PRI * HTTP/2";
+ char buffer[sizeof(magic)] = { 0 };
+ bpf_probe_read(buffer, sizeof(buffer) - 1, buf_src);
+ for (int idx = 0; idx < sizeof(magic); ++idx) {
+ if (magic[idx] == buffer[idx])
+ continue;
+ return false;
+ }
+ return true;
+}
// HTTP 2.x
// frame format: https://www.rfc-editor.org/rfc/rfc7540.html#section-4.1
@@ -97,6 +109,10 @@ static __inline __u32 infer_http2_message(const char* buf, size_t count) {
// header info
__u8 staticInx, headerBlockFragmentOffset;
+ if (is_http2_magic(buf, count)) {
+ frameOffset = 24;
+ }
+
// each all frame
#pragma unroll
for (__u8 i = 0; i < kFrameLoopCount; i++) {
diff --git a/bpf/profiling/network/socket.h b/bpf/include/socket.h
similarity index 83%
rename from bpf/profiling/network/socket.h
rename to bpf/include/socket.h
index ee0a294..b446bbb 100644
--- a/bpf/profiling/network/socket.h
+++ b/bpf/include/socket.h
@@ -62,9 +62,21 @@ struct socket {
struct sock *sk;
} __attribute__((preserve_access_index));
+struct iov_iter {
+ __u64 count;
+ union {
+ const struct iovec *iov;
+ const struct kvec *kvec;
+ const struct bio_vec *bvec;
+ struct xarray *xarray;
+ struct pipe_inode_info *pipe;
+ };
+} __attribute__((preserve_access_index));
+
struct sock {
- struct sock_common __sk_common;
+ struct sock_common __sk_common;
struct socket *sk_socket;
+ __u32 sk_max_ack_backlog;
} __attribute__((preserve_access_index));
struct tcp_sock {
@@ -95,7 +107,20 @@ struct rb_node {
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((preserve_access_index));
+
struct sk_buff {
+ union {
+ struct {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ union {
+ struct net_device *dev;
+ long unsigned int dev_scratch;
+ };
+ } __attribute__((preserve_access_index));
+ struct rb_node rbnode;
+ struct list_head list;
+ };
struct sock *sk;
union {
struct {
@@ -111,6 +136,8 @@ struct sk_buff {
int skb_iif;
unsigned int len;
unsigned int data_len;
+ unsigned char *head,
+ *data;
} __attribute__((preserve_access_index));
struct net {
diff --git a/bpf/include/socket_opts.h b/bpf/include/socket_opts.h
new file mode 100644
index 0000000..8aeafca
--- /dev/null
+++ b/bpf/include/socket_opts.h
@@ -0,0 +1,57 @@
+// 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.
+
+#pragma once
+
+// the socket operation type
+#define SOCKET_OPTS_TYPE_CONNECT 1
+#define SOCKET_OPTS_TYPE_ACCEPT 2
+#define SOCKET_OPTS_TYPE_CLOSE 3
+#define SOCKET_OPTS_TYPE_SEND 4
+#define SOCKET_OPTS_TYPE_SENDTO 5
+#define SOCKET_OPTS_TYPE_SENDMSG 6
+#define SOCKET_OPTS_TYPE_SENDMMSG 7
+#define SOCKET_OPTS_TYPE_SENDFILE 8
+#define SOCKET_OPTS_TYPE_WRITE 9
+#define SOCKET_OPTS_TYPE_WRITEV 10
+#define SOCKET_OPTS_TYPE_READ 11
+#define SOCKET_OPTS_TYPE_READV 12
+#define SOCKET_OPTS_TYPE_RECV 13
+#define SOCKET_OPTS_TYPE_RECVFROM 14
+#define SOCKET_OPTS_TYPE_RECVMSG 15
+#define SOCKET_OPTS_TYPE_RECVMMSG 16
+#define SOCKET_OPTS_TYPE_RESENT 17
+#define SOCKET_OPTS_TYPE_SSL_WRITE 18
+#define SOCKET_OPTS_TYPE_SSL_READ 19
+#define SOCKET_OPTS_TYPE_GOTLS_WRITE 20
+#define SOCKET_OPTS_TYPE_GOTLS_READ 21
+
+// for protocol analyze need to read
+#define MAX_PROTOCOL_SOCKET_READ_LENGTH 31
+// for transmit to the user space
+#define MAX_TRANSMIT_SOCKET_READ_LENGTH 2047
+
+// unknown the connection type, not trigger the syscall connect,accept
+#define AF_UNKNOWN 0xff
+
+#define CONNECTION_ROLE_TYPE_UNKNOWN 0
+#define CONNECTION_ROLE_TYPE_CLIENT 1
+#define CONNECTION_ROLE_TYPE_SERVER 2
+
+// data direction
+#define SOCK_DATA_DIRECTION_INGRESS 1 //receive from
+#define SOCK_DATA_DIRECTION_EGRESS 2 //write to
diff --git a/bpf/include/socket_reader.h b/bpf/include/socket_reader.h
new file mode 100644
index 0000000..28b177d
--- /dev/null
+++ b/bpf/include/socket_reader.h
@@ -0,0 +1,64 @@
+// 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.
+
+#pragma once
+
+#include "socket_opts.h"
+
+struct socket_buffer_reader_t {
+ __u32 data_len;
+ char buffer[MAX_PROTOCOL_SOCKET_READ_LENGTH + 1];
+};
+struct {
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+ __type(key, __u32);
+ __type(value, struct socket_buffer_reader_t);
+ __uint(max_entries, 1);
+} socket_buffer_reader_map SEC(".maps");
+
+static __inline struct socket_buffer_reader_t* read_socket_data(char* buf, struct iovec *iovec, __u32 bytes_count) {
+ __u64 size = 0;
+ __u32 kZero = 0;
+ char* data_buf;
+ struct socket_buffer_reader_t* reader = bpf_map_lookup_elem(&socket_buffer_reader_map, &kZero);
+ if (reader == NULL) {
+ return NULL;
+ }
+ if (buf != NULL) {
+ data_buf = buf;
+ size = bytes_count;
+ } else if (iovec != NULL) {
+ struct iovec iov;
+ bpf_probe_read(&iov, sizeof(iov), iovec);
+ __u64 tmp = iov.iov_len;
+ if (tmp > bytes_count) {
+ tmp = bytes_count;
+ }
+ data_buf = (char *)iov.iov_base;
+ size = tmp;
+ }
+ if (size <= 0) {
+ return NULL;
+ }
+ if (size > MAX_PROTOCOL_SOCKET_READ_LENGTH) {
+ size = MAX_PROTOCOL_SOCKET_READ_LENGTH;
+ }
+ asm volatile("%[size] &= 0x1f;\n" ::[size] "+r"(size) :);
+ bpf_probe_read(&reader->buffer, size & MAX_PROTOCOL_SOCKET_READ_LENGTH, data_buf);
+ reader->data_len = size & MAX_PROTOCOL_SOCKET_READ_LENGTH;
+ return reader;
+}
\ No newline at end of file
diff --git a/bpf/profiling/continuous/network.c b/bpf/profiling/continuous/network.c
index b4591aa..42aa6c5 100644
--- a/bpf/profiling/continuous/network.c
+++ b/bpf/profiling/continuous/network.c
@@ -30,6 +30,7 @@
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
+#include <sys/uio.h>
#include "network.h"
#include "protocol_analyzer.h"
@@ -85,10 +86,10 @@ static __always_inline void process_data(struct pt_regs *ctx, __u64 id, void *ch
static __always_inline void process_msghdr_data(struct pt_regs *ctx, __u64 id, void *channel_ref, struct msghdr *msg) {
const struct iovec *iovec;
iovec = _KERNEL(msg->msg_iter.iov);
- struct iovec iov;
- bpf_probe_read(&iov, sizeof(iov), iovec);
- char* buf = (char *)iov.iov_base;
- __u64 size = iov.iov_len;
+ struct iovec iov_data;
+ bpf_probe_read(&iov_data, sizeof(iov_data), iovec);
+ char* buf = (char *)iov_data.iov_base;
+ __u64 size = iov_data.iov_len;
return process_data(ctx, id, channel_ref, buf, size, bpf_ktime_get_ns());
}
diff --git a/bpf/profiling/continuous/network.h b/bpf/profiling/continuous/network.h
index 461b037..29735a7 100644
--- a/bpf/profiling/continuous/network.h
+++ b/bpf/profiling/continuous/network.h
@@ -16,7 +16,7 @@
// under the License.
#include "api.h"
-#include "skb.h"
+#include "socket.h"
#define MAX_PROTOCOL_SOCKET_READ_LENGTH 255
@@ -63,4 +63,9 @@ struct {
} socket_buffer_reader_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
-} socket_buffer_send_queue SEC(".maps");
\ No newline at end of file
+} socket_buffer_send_queue SEC(".maps");
+
+struct msghdr {
+ struct iov_iter msg_iter; /* data */
+ unsigned int msg_flags;
+} __attribute__((preserve_access_index));
\ No newline at end of file
diff --git a/bpf/profiling/network/args.h b/bpf/profiling/network/args.h
index f61b134..418edfe 100644
--- a/bpf/profiling/network/args.h
+++ b/bpf/profiling/network/args.h
@@ -17,40 +17,10 @@
#include "api.h"
#include "socket.h"
+#include "socket_opts.h"
#pragma once
-// for protocol analyze need to read
-#define MAX_PROTOCOL_SOCKET_READ_LENGTH 31
-// for transmit to the user space
-#define MAX_TRANSMIT_SOCKET_READ_LENGTH 2047
-
-// unknown the connection type, not trigger the syscall connect,accept
-#define AF_UNKNOWN 0xff
-
-// the socket operation type
-#define SOCKET_OPTS_TYPE_CONNECT 1
-#define SOCKET_OPTS_TYPE_ACCEPT 2
-#define SOCKET_OPTS_TYPE_CLOSE 3
-#define SOCKET_OPTS_TYPE_SEND 4
-#define SOCKET_OPTS_TYPE_SENDTO 5
-#define SOCKET_OPTS_TYPE_SENDMSG 6
-#define SOCKET_OPTS_TYPE_SENDMMSG 7
-#define SOCKET_OPTS_TYPE_SENDFILE 8
-#define SOCKET_OPTS_TYPE_WRITE 9
-#define SOCKET_OPTS_TYPE_WRITEV 10
-#define SOCKET_OPTS_TYPE_READ 11
-#define SOCKET_OPTS_TYPE_READV 12
-#define SOCKET_OPTS_TYPE_RECV 13
-#define SOCKET_OPTS_TYPE_RECVFROM 14
-#define SOCKET_OPTS_TYPE_RECVMSG 15
-#define SOCKET_OPTS_TYPE_RECVMMSG 16
-#define SOCKET_OPTS_TYPE_RESENT 17
-#define SOCKET_OPTS_TYPE_SSL_WRITE 18
-#define SOCKET_OPTS_TYPE_SSL_READ 19
-#define SOCKET_OPTS_TYPE_GOTLS_WRITE 20
-#define SOCKET_OPTS_TYPE_GOTLS_READ 21
-
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10000);
@@ -119,10 +89,6 @@ struct {
__type(value, struct accept_args_t);
} accepting_args SEC(".maps");
-// data direction
-#define SOCK_DATA_DIRECTION_INGRESS 1 //receive from
-#define SOCK_DATA_DIRECTION_EGRESS 2 //write to
-
// syscall: data writing or receive
struct sock_data_args_t {
__u32 fd;
diff --git a/configs/rover_configs.yaml b/configs/rover_configs.yaml
index 90132d5..05859b0 100644
--- a/configs/rover_configs.yaml
+++ b/configs/rover_configs.yaml
@@ -151,4 +151,20 @@ profiling:
# the duration of the profiling task
execute_duration: ${ROVER_PROFILING_CONTINUOUS_TRIGGER_EXECUTE_DURATION:10m}
# the minimal duration between the execution of the same profiling task
- silence_duration: ${ROVER_PROFILING_CONTINUOUS_TRIGGER_SILENCE_DURATION:20m}
\ No newline at end of file
+ silence_duration: ${ROVER_PROFILING_CONTINUOUS_TRIGGER_SILENCE_DURATION:20m}
+
+access_log:
+ # Is active the access log monitoring
+ active: ${ROVER_ACCESS_LOG_ACTIVE:false}
+ flush:
+ # The max count of access log when flush to the backend
+ max_count: ${ROVER_ACCESS_LOG_FLUSH_MAX_COUNT:2000}
+ # The period of flush access log to the backend
+ period: ${ROVER_ACCESS_LOG_FLUSH_PERIOD:5s}
+ protocol_analyze:
+ # The size of socket data buffer on each CPU
+ per_cpu_buffer: ${ROVER_ACCESS_LOG_PROTOCOL_ANALYZE_PER_CPU_BUFFER:400KB}
+ # The count of parallel protocol analyzer
+ parallels: ${ROVER_ACCESS_LOG_PROTOCOL_ANALYZE_PARALLELS:2}
+ # The size of per paralleled analyzer queue
+ queue_size: ${ROVER_ACCESS_LOG_PROTOCOL_ANALYZE_QUEUE_SIZE:5000}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 7dea1cc..94fc0b8 100644
--- a/go.mod
+++ b/go.mod
@@ -18,14 +18,14 @@ require (
github.com/stretchr/testify v1.8.1
github.com/zekroTJA/timedmap v1.4.0
golang.org/x/arch v0.0.0-20220722155209-00200b7164a7
- golang.org/x/net v0.6.0
- golang.org/x/sys v0.5.0
+ golang.org/x/net v0.17.0
+ golang.org/x/sys v0.13.0
google.golang.org/grpc v1.44.0
k8s.io/api v0.23.5
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-20230301143132-aa3f8469385b
+ skywalking.apache.org/repo/goapi v0.0.0-20231225085619-53f5be6739c4
)
require (
@@ -57,12 +57,12 @@ require (
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
- golang.org/x/term v0.5.0 // indirect
- golang.org/x/text v0.7.0 // indirect
+ golang.org/x/term v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
- google.golang.org/protobuf v1.28.1 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 3a3798e..f9e5af8 100644
--- a/go.sum
+++ b/go.sum
@@ -478,6 +478,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -515,6 +516,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -561,8 +563,10 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -593,6 +597,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -668,13 +673,17 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -684,8 +693,10 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -748,6 +759,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -901,8 +913,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -964,5 +976,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-20230301143132-aa3f8469385b h1:VAWQr1mJk4P/a8VZ9UASY8H53wj0zdLHgYvhddyQcXw=
-skywalking.apache.org/repo/goapi v0.0.0-20230301143132-aa3f8469385b/go.mod h1:WovoDv1GA+8VuvHPVJL7q/fL0KlYPBZq5rTMCFQRzJU=
+skywalking.apache.org/repo/goapi v0.0.0-20231225085619-53f5be6739c4 h1:boI2sHrjhiXdidajUn1KyVNC7CvC/pwIn9zr52TuXBQ=
+skywalking.apache.org/repo/goapi v0.0.0-20231225085619-53f5be6739c4/go.mod h1:oD2dxcDAHVIt95Ee7kJHgZ5f64QNhrqTjQYARwfafc4=
diff --git a/pkg/tools/host/network.go b/pkg/accesslog/bpf/loader.go
similarity index 50%
copy from pkg/tools/host/network.go
copy to pkg/accesslog/bpf/loader.go
index 34f24de..5a4f827 100644
--- a/pkg/tools/host/network.go
+++ b/pkg/accesslog/bpf/loader.go
@@ -15,48 +15,42 @@
// specific language governing permissions and limitations
// under the License.
-package host
+package bpf
import (
- "net"
+ "github.com/hashicorp/go-multierror"
- "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
)
-var interfaces map[int]*net.Interface
-var log = logger.GetLogger("tools", "host")
+// $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
+// nolint
+//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target $TARGET -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf $REPO_ROOT/bpf/accesslog/accesslog.c -- -I$REPO_ROOT/bpf/include
-func init() {
- if err := refreshInterfaces(); err != nil {
- panic(err)
- }
+type Loader struct {
+ *btf.Linker
+ *bpfObjects
}
-func NetworkName(ifindex int) string {
- i := interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- if e := refreshInterfaces(); e != nil {
- log.Warnf("error to refresh interfaces: %v", e)
- return ""
+func NewLoader() (*Loader, error) {
+ objs := bpfObjects{}
+ if err := loadBpfObjects(&objs, btf.GetEBPFCollectionOptionsIfNeed()); err != nil {
+ return nil, err
}
- i = interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- return ""
+
+ return &Loader{
+ bpfObjects: &objs,
+ Linker: btf.NewLinker(),
+ }, nil
}
-func refreshInterfaces() error {
- results, err := net.Interfaces()
- if err != nil {
- return err
+func (l *Loader) Close() error {
+ var err error
+ if e := l.bpfObjects.Close(); e != nil {
+ err = multierror.Append(err, e)
}
- tmp := make(map[int]*net.Interface)
- for _, interf := range results {
- tmp[interf.Index] = &interf
+ if e := l.Linker.Close(); e != nil {
+ err = multierror.Append(err, e)
}
- interfaces = tmp
- return nil
+ return err
}
diff --git a/pkg/accesslog/collector/close.go b/pkg/accesslog/collector/close.go
new file mode 100644
index 0000000..27bfbec
--- /dev/null
+++ b/pkg/accesslog/collector/close.go
@@ -0,0 +1,56 @@
+// 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 (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/module"
+)
+
+var closeLog = logger.GetLogger("access_log", "collector", "close")
+
+var closeCollectorInstance = NewCloseCollector()
+
+type CloseCollector struct {
+}
+
+func NewCloseCollector() *CloseCollector {
+ return &CloseCollector{}
+}
+
+func (c *CloseCollector) Start(_ *module.Manager, context *common.AccessLogContext) error {
+ context.BPF.AddTracePoint("syscalls", "sys_enter_close", context.BPF.TracepointEnterClose)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_close", context.BPF.TracepointExitClose)
+
+ context.BPF.ReadEventAsync(context.BPF.SocketCloseEventQueue, func(data interface{}) {
+ event := data.(*events.SocketCloseEvent)
+ closeLog.Debugf("receive close event, connection ID: %d, randomID: %d, pid: %d, fd: %d",
+ event.ConnectionID, event.RandomID, event.PID, event.SocketFD)
+ wapperedEvent := context.ConnectionMgr.OnConnectionClose(event)
+ forwarder.SendCloseEvent(context, wapperedEvent)
+ }, func() interface{} {
+ return &events.SocketCloseEvent{}
+ })
+ return nil
+}
+
+func (c *CloseCollector) Stop() {
+}
diff --git a/bpf/profiling/continuous/skb.h b/pkg/accesslog/collector/collector.go
similarity index 59%
rename from bpf/profiling/continuous/skb.h
rename to pkg/accesslog/collector/collector.go
index ed1a9ed..e7d6e9b 100644
--- a/bpf/profiling/continuous/skb.h
+++ b/pkg/accesslog/collector/collector.go
@@ -15,28 +15,25 @@
// specific language governing permissions and limitations
// under the License.
-struct iovec {
- void *iov_base;
- __u64 iov_len;
-} __attribute__((preserve_access_index));
+package collector
-struct iov_iter {
- __u64 count;
- union {
- const struct iovec *iov;
- const struct kvec *kvec;
- const struct bio_vec *bvec;
- struct xarray *xarray;
- struct pipe_inode_info *pipe;
- };
-} __attribute__((preserve_access_index));
+import (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/module"
+)
-struct msghdr {
- struct iov_iter msg_iter; /* data */
- unsigned int msg_flags;
-} __attribute__((preserve_access_index));
+type Collector interface {
+ Start(mgr *module.Manager, context *common.AccessLogContext) error
+ Stop()
+}
-struct sock {
- struct socket *sk_socket;
- __u32 sk_max_ack_backlog;
-} __attribute__((preserve_access_index));
\ No newline at end of file
+func Collectors() []Collector {
+ return []Collector{
+ l24CollectorsInstance,
+ transferCollectInstance,
+ closeCollectorInstance,
+ connectCollectInstance,
+ tlsCollectInstance,
+ processCollectInstance,
+ }
+}
diff --git a/pkg/accesslog/collector/connect.go b/pkg/accesslog/collector/connect.go
new file mode 100644
index 0000000..a93a215
--- /dev/null
+++ b/pkg/accesslog/collector/connect.go
@@ -0,0 +1,162 @@
+// 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 (
+ "encoding/binary"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/module"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/ip"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/link"
+
+ "golang.org/x/sys/unix"
+)
+
+var connectLogger = logger.GetLogger("access_log", "collector", "connect")
+
+var connectCollectInstance = NewConnectCollector()
+
+type ConnectCollector struct {
+}
+
+func NewConnectCollector() *ConnectCollector {
+ return &ConnectCollector{}
+}
+
+func (c *ConnectCollector) Start(_ *module.Manager, context *common.AccessLogContext) error {
+ context.BPF.AddTracePoint("syscalls", "sys_enter_connect", context.BPF.TracepointEnterConnect)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_connect", context.BPF.TracepointExitConnect)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_accept", context.BPF.TracepointEnterAccept)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_accept", context.BPF.TracepointExitAccept)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_accept4", context.BPF.TracepointEnterAccept)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_accept4", context.BPF.TracepointExitAccept)
+
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{
+ "tcp_connect": context.BPF.TcpConnect,
+ })
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{
+ "sock_alloc": context.BPF.SockAllocRet,
+ })
+
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{
+ "__nf_conntrack_hash_insert": context.BPF.NfConntrackHashInsert,
+ "nf_confirm": context.BPF.NfConfirm,
+ })
+
+ context.BPF.ReadEventAsync(context.BPF.SocketConnectionEventQueue, func(data interface{}) {
+ event := data.(*events.SocketConnectEvent)
+ connectLogger.Debugf("receive connect event, connection ID: %d, randomID: %d, pid: %d, fd: %d, role: %s: func: %s, family: %d, success: %d",
+ event.ConID, event.RandomID, event.PID, event.SocketFD, enums.ConnectionRole(event.Role), enums.SocketFunctionName(event.FuncName),
+ event.SocketFamily, event.ConnectSuccess)
+ socketPair := buildSocketFromConnectEvent(event)
+ if socketPair == nil {
+ connectLogger.Debugf("cannot found the socket paire from connect event, connection ID: %d, randomID: %d",
+ event.ConID, event.RandomID)
+ return
+ }
+ context.ConnectionMgr.OnConnectEvent(event, socketPair)
+ forwarder.SendConnectEvent(context, event, socketPair)
+ }, func() interface{} {
+ return &events.SocketConnectEvent{}
+ })
+
+ return nil
+}
+
+func (c *ConnectCollector) Stop() {
+}
+
+func buildSocketFromConnectEvent(event *events.SocketConnectEvent) *ip.SocketPair {
+ if event.SocketFamily != unix.AF_INET && event.SocketFamily != unix.AF_INET6 && event.SocketFamily != enums.SocketFamilyUnknown {
+ // if not ipv4, ipv6 or unknown, ignore
+ return nil
+ }
+ socketPair := buildSocketPair(event)
+ if socketPair != nil && socketPair.IsValid() {
+ return socketPair
+ }
+ // if only the local port not success, maybe the upstream port is not open, so it could be continued
+ if isOnlyLocalPortEmpty(socketPair) {
+ event.ConnectSuccess = 0
+ return socketPair
+ }
+
+ pair, err := ip.ParseSocket(event.PID, event.SocketFD)
+ if err != nil {
+ connectLogger.Warnf("cannot found the socket, pid: %d, socket FD: %d", event.PID, event.SocketFD)
+ return nil
+ }
+ pair.Role = enums.ConnectionRole(event.Role)
+ return pair
+}
+
+func isOnlyLocalPortEmpty(socketPair *ip.SocketPair) bool {
+ if socketPair == nil {
+ return false
+ }
+ port := socketPair.SrcPort
+ defer func() {
+ socketPair.SrcPort = port
+ }()
+ socketPair.SrcPort = 1
+ return socketPair.IsValid()
+}
+
+func buildSocketPair(event *events.SocketConnectEvent) *ip.SocketPair {
+ var result *ip.SocketPair
+ if event.SocketFamily == unix.AF_INET {
+ result = &ip.SocketPair{
+ Family: uint32(event.SocketFamily),
+ Role: enums.ConnectionRoleClient,
+ SrcIP: ip.ParseIPV4(event.LocalAddrV4),
+ SrcPort: uint16(event.LocalAddrPort),
+ }
+ if event.ConnTrackUpstreamIPl != 0 && event.ConnTrackUpstreamPort != 0 {
+ result.DestIP = ip.ParseIPV4(uint32(event.ConnTrackUpstreamIPl))
+ result.DestPort = uint16(event.ConnTrackUpstreamPort)
+ } else {
+ result.DestIP = ip.ParseIPV4(event.RemoteAddrV4)
+ result.DestPort = uint16(event.RemoteAddrPort)
+ }
+ } else if event.SocketFamily == unix.AF_INET6 {
+ result = &ip.SocketPair{
+ Family: uint32(event.SocketFamily),
+ Role: enums.ConnectionRoleClient,
+ SrcIP: ip.ParseIPV6(event.LocalAddrV6),
+ SrcPort: uint16(event.LocalAddrPort),
+ }
+ if event.ConnTrackUpstreamIPl != 0 && event.ConnTrackUpstreamPort != 0 {
+ var ipv6 [16]uint8
+ binary.BigEndian.PutUint64(ipv6[0:8], event.ConnTrackUpstreamIPh)
+ binary.BigEndian.PutUint64(ipv6[8:16], event.ConnTrackUpstreamIPl)
+ result.DestIP = ip.ParseIPV6(ipv6)
+ result.DestPort = uint16(event.ConnTrackUpstreamPort)
+ } else {
+ result.DestIP = ip.ParseIPV6(event.RemoteAddrV6)
+ result.DestPort = uint16(event.RemoteAddrPort)
+ }
+ }
+ return result
+}
diff --git a/pkg/accesslog/collector/l24.go b/pkg/accesslog/collector/l24.go
new file mode 100644
index 0000000..109617a
--- /dev/null
+++ b/pkg/accesslog/collector/l24.go
@@ -0,0 +1,93 @@
+// 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 (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/module"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/link"
+)
+
+var l24CollectorsInstance = NewL24Collector()
+
+type L24Collector struct {
+}
+
+func NewL24Collector() *L24Collector {
+ return &L24Collector{}
+}
+
+func (c *L24Collector) Start(mgr *module.Manager, context *common.AccessLogContext) error {
+ c.startWrite(mgr, context)
+ c.startRead(mgr, context)
+ return nil
+}
+
+func (c *L24Collector) startRead(_ *module.Manager, context *common.AccessLogContext) {
+ // l2
+ context.BPF.AddTracePoint("net", "netif_receive_skb", context.BPF.TracepointNetifReceiveSkb)
+
+ // l3
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_list_rcv": context.BPF.IpListRcv})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"ip_list_rcv": context.BPF.IpListRcvRet})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_rcv": context.BPF.IpRcv})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"ip_rcv": context.BPF.IpRcvRet})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_rcv_finish": context.BPF.IpRcvFinish})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_sublist_rcv_finish": context.BPF.IpSublistRcvFinish})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_local_deliver": context.BPF.IpLocalDeliver})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_local_deliver_finish": context.BPF.IpLocalDeliverFinish})
+
+ // l4
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"tcp_v4_rcv": context.BPF.TcpV4Rcv})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"tcp_v4_rcv": context.BPF.TcpV4RcvRet})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"tcp_v6_rcv": context.BPF.TcpV6Rcv})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"tcp_v6_rcv": context.BPF.TcpV6RcvRet})
+}
+
+func (c *L24Collector) startWrite(_ *module.Manager, context *common.AccessLogContext) {
+ // l4
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"tcp_sendmsg": context.BPF.TcpSendmsg})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"tcp_sendmsg": context.BPF.TcpSendmsgRet})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"__tcp_transmit_skb": context.BPF.TcpTransmitSkb})
+ context.BPF.AddTracePoint("tcp", "tcp_retransmit_skb", context.BPF.TracepointTcpRetransmitSkb)
+ context.BPF.AddTracePoint("skb", "kfree_skb", context.BPF.KfreeSkb)
+
+ // l3
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"__ip_queue_xmit": context.BPF.IpQueueXmit})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"__ip_queue_xmit": context.BPF.IpQueueXmitRet})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"__ip_local_out": context.BPF.IpLocal})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_output": context.BPF.IpOutput})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"ip_finish_output2": context.BPF.IpFinishOutput2})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"neigh_resolve_output": context.BPF.NeighResolveOutput})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"neigh_resolve_output": context.BPF.NeighResolveOutputRet})
+
+ // netlink
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"nf_hook_slow": context.BPF.NfHookSlow})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"nf_hook_slow": context.BPF.NfHookSlowRet})
+
+ // l2
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"__dev_queue_xmit": context.BPF.DevQueueEmit})
+ context.BPF.AddLink(link.Kretprobe, map[string]*ebpf.Program{"__dev_queue_xmit": context.BPF.DevQueueEmitRet})
+ context.BPF.AddTracePoint("net", "net_dev_start_xmit", context.BPF.TracepointNetDevStartXmit)
+ context.BPF.AddTracePoint("net", "net_dev_xmit", context.BPF.TracepointNetDevXmit)
+}
+
+func (c *L24Collector) Stop() {
+}
diff --git a/pkg/boot/register.go b/pkg/accesslog/collector/process.go
similarity index 50%
copy from pkg/boot/register.go
copy to pkg/accesslog/collector/process.go
index 8f0d64d..e4dbdce 100644
--- a/pkg/boot/register.go
+++ b/pkg/accesslog/collector/process.go
@@ -15,20 +15,39 @@
// specific language governing permissions and limitations
// under the License.
-package boot
+package collector
import (
- "github.com/apache/skywalking-rover/pkg/core"
- "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
"github.com/apache/skywalking-rover/pkg/module"
- "github.com/apache/skywalking-rover/pkg/process"
- "github.com/apache/skywalking-rover/pkg/profiling"
)
-func init() {
- // register all active module
- module.Register(logger.NewModule())
- module.Register(core.NewModule())
- module.Register(process.NewModule())
- module.Register(profiling.NewModule())
+var processCollectInstance = NewProcessCollector()
+
+// ProcessCollector Management all processes which needs to be monitored
+type ProcessCollector struct {
+}
+
+func NewProcessCollector() *ProcessCollector {
+ return &ProcessCollector{}
+}
+
+func (p *ProcessCollector) Start(_ *module.Manager, context *common.AccessLogContext) error {
+ // monitor process been execute
+ context.BPF.AddTracePoint("sched", "sched_process_fork", context.BPF.TracepointSchedProcessFork)
+
+ context.BPF.ReadEventAsync(context.BPF.ProcessExecuteQueue, func(data interface{}) {
+ context.ConnectionMgr.OnNewProcessExecuting(int32(data.(*ProcessExecuteEvent).PID))
+ }, func() interface{} {
+ return &ProcessExecuteEvent{}
+ })
+
+ return nil
+}
+
+func (p *ProcessCollector) Stop() {
+}
+
+type ProcessExecuteEvent struct {
+ PID uint32
}
diff --git a/pkg/accesslog/collector/protocols/http1.go b/pkg/accesslog/collector/protocols/http1.go
new file mode 100644
index 0000000..e25b5c1
--- /dev/null
+++ b/pkg/accesslog/collector/protocols/http1.go
@@ -0,0 +1,234 @@
+// 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 protocols
+
+import (
+ "container/list"
+ "io"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+var http1Log = logger.GetLogger("accesslog", "collector", "protocols", "http1")
+
+func init() {
+ registeredProtocols[enums.ConnectionProtocolHTTP] = func(ctx *common.AccessLogContext) Protocol {
+ return &HTTP1Protocol{ctx: ctx}
+ }
+}
+
+type HTTP1Protocol struct {
+ ctx *common.AccessLogContext
+}
+
+type HTTP1Metrics struct {
+ halfRequests *list.List
+}
+
+func (p *HTTP1Protocol) GenerateConnection(connectionID uint64) ProtocolMetrics {
+ return &HTTP1Metrics{
+ halfRequests: list.New(),
+ }
+}
+
+func (p *HTTP1Protocol) Analyze(metrics ProtocolMetrics, buf *buffer.Buffer, _ *AnalyzeHelper) error {
+ buf.ResetForLoopReading()
+ for {
+ if !buf.PrepareForReading() {
+ return nil
+ }
+
+ messageType, err := reader.IdentityMessageType(buf)
+ if err != nil {
+ http1Log.Debugf("failed to identity message type, %v", err)
+ if buf.SkipCurrentElement() {
+ break
+ }
+ continue
+ }
+
+ var result enums.ParseResult
+ switch messageType {
+ case reader.MessageTypeRequest:
+ result, _ = p.handleRequest(metrics, buf)
+ case reader.MessageTypeResponse:
+ result, _ = p.handleResponse(metrics, buf)
+ case reader.MessageTypeUnknown:
+ result = enums.ParseResultSkipPackage
+ }
+
+ finishReading := false
+ switch result {
+ case enums.ParseResultSuccess:
+ finishReading = buf.RemoveReadElements()
+ case enums.ParseResultSkipPackage:
+ finishReading = buf.SkipCurrentElement()
+ }
+
+ if finishReading {
+ break
+ }
+ }
+ return nil
+}
+
+func (p *HTTP1Protocol) handleRequest(metrics ProtocolMetrics, buf *buffer.Buffer) (enums.ParseResult, error) {
+ req, result, err := reader.ReadRequest(buf, true)
+ if err != nil {
+ return enums.ParseResultSkipPackage, err
+ }
+ if result != enums.ParseResultSuccess {
+ return result, nil
+ }
+ metrics.(*HTTP1Metrics).appendRequestToList(req)
+ return result, nil
+}
+
+func (p *HTTP1Protocol) handleResponse(metrics ProtocolMetrics, b *buffer.Buffer) (enums.ParseResult, error) {
+ http1Metrics := metrics.(*HTTP1Metrics)
+ firstRequest := http1Metrics.halfRequests.Front()
+ if firstRequest == nil {
+ return enums.ParseResultSkipPackage, nil
+ }
+ request := http1Metrics.halfRequests.Remove(firstRequest).(*reader.Request)
+
+ // parsing response
+ response, result, err := reader.ReadResponse(request, b, true)
+ defer func() {
+ // if parsing response failed, then put the request back to the list
+ if result != enums.ParseResultSuccess {
+ http1Metrics.halfRequests.PushFront(request)
+ }
+ }()
+ if err != nil {
+ return enums.ParseResultSkipPackage, err
+ } else if result != enums.ParseResultSuccess {
+ return result, nil
+ }
+
+ // getting the request and response, then send to the forwarder
+ p.handleHTTPData(request, response)
+ return enums.ParseResultSuccess, nil
+}
+
+func (p *HTTP1Protocol) handleHTTPData(request *reader.Request, response *reader.Response) {
+ detailEvents := make([]*events.SocketDetailEvent, 0)
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, request.HeaderBuffer())
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, request.BodyBuffer())
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, response.HeaderBuffer())
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, response.BodyBuffer())
+
+ if len(detailEvents) == 0 {
+ http1Log.Warnf("cannot found any detail events for HTTP/1.x protocol, data id: %d-%d",
+ request.MinDataID(), response.BodyBuffer().LastSocketBuffer().DataID())
+ return
+ }
+ originalRequest := request.Original()
+ originalResponse := response.Original()
+
+ defer func() {
+ p.closeStream(originalRequest.Body)
+ p.closeStream(originalResponse.Body)
+ }()
+ forwarder.SendTransferProtocolEvent(p.ctx, detailEvents, &v3.AccessLogProtocolLogs{
+ Protocol: &v3.AccessLogProtocolLogs_Http{
+ Http: &v3.AccessLogHTTPProtocol{
+ StartTime: forwarder.BuildOffsetTimestamp(detailEvents[0].StartTime),
+ EndTime: forwarder.BuildOffsetTimestamp(detailEvents[len(detailEvents)-1].EndTime),
+ Version: v3.AccessLogHTTPProtocolVersion_HTTP1,
+ Request: &v3.AccessLogHTTPProtocolRequest{
+ Method: transformHTTPMethod(originalRequest.Method),
+ Path: originalRequest.URL.Path,
+ SizeOfHeadersBytes: uint64(request.HeaderBuffer().DataSize()),
+ SizeOfBodyBytes: uint64(request.BodyBuffer().DataSize()),
+
+ Trace: analyzeTraceInfo(func(key string) string {
+ return originalRequest.Header.Get(key)
+ }, http1Log),
+ },
+ Response: &v3.AccessLogHTTPProtocolResponse{
+ StatusCode: int32(originalResponse.StatusCode),
+ SizeOfHeadersBytes: uint64(response.HeaderBuffer().DataSize()),
+ SizeOfBodyBytes: uint64(response.BodyBuffer().DataSize()),
+ },
+ },
+ },
+ })
+}
+
+func (p *HTTP1Protocol) closeStream(ioReader io.Closer) {
+ if ioReader != nil {
+ _ = ioReader.Close()
+ }
+}
+
+func transformHTTPMethod(method string) v3.AccessLogHTTPProtocolRequestMethod {
+ switch method {
+ case "GET":
+ return v3.AccessLogHTTPProtocolRequestMethod_Get
+ case "POST":
+ return v3.AccessLogHTTPProtocolRequestMethod_Post
+ case "PUT":
+ return v3.AccessLogHTTPProtocolRequestMethod_Put
+ case "DELETE":
+ return v3.AccessLogHTTPProtocolRequestMethod_Delete
+ case "HEAD":
+ return v3.AccessLogHTTPProtocolRequestMethod_Head
+ case "OPTIONS":
+ return v3.AccessLogHTTPProtocolRequestMethod_Options
+ case "TRACE":
+ return v3.AccessLogHTTPProtocolRequestMethod_Trace
+ case "CONNECT":
+ return v3.AccessLogHTTPProtocolRequestMethod_Connect
+ case "PATCH":
+ return v3.AccessLogHTTPProtocolRequestMethod_Patch
+ }
+ http1Log.Warnf("unknown http method: %s", method)
+ return v3.AccessLogHTTPProtocolRequestMethod_Get
+}
+
+func (m *HTTP1Metrics) appendRequestToList(req *reader.Request) {
+ if m.halfRequests.Len() == 0 {
+ m.halfRequests.PushFront(req)
+ return
+ }
+ if m.halfRequests.Back().Value.(*reader.Request).MinDataID() < req.MinDataID() {
+ m.halfRequests.PushBack(req)
+ return
+ }
+ beenAdded := false
+ for element := m.halfRequests.Front(); element != nil; element = element.Next() {
+ existEvent := element.Value.(*reader.Request)
+ if existEvent.MinDataID() > req.MinDataID() {
+ m.halfRequests.InsertBefore(req, element)
+ beenAdded = true
+ break
+ }
+ }
+ if !beenAdded {
+ m.halfRequests.PushBack(req)
+ }
+}
diff --git a/pkg/accesslog/collector/protocols/http2.go b/pkg/accesslog/collector/protocols/http2.go
new file mode 100644
index 0000000..f9a2e3d
--- /dev/null
+++ b/pkg/accesslog/collector/protocols/http2.go
@@ -0,0 +1,314 @@
+// 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 protocols
+
+import (
+ "errors"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/hpack"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+// maxHTTP2StreamingTime is the max time of an HTTP/2 streaming, if the streaming is too long, then this streaming will split
+var maxHTTP2StreamingTime = time.Minute * 3
+
+var http2Log = logger.GetLogger("accesslog", "collector", "protocols", "http2")
+
+func init() {
+ registeredProtocols[enums.ConnectionProtocolHTTP2] = func(ctx *common.AccessLogContext) Protocol {
+ return &HTTP2Protocol{ctx: ctx}
+ }
+}
+
+type HTTP2Protocol struct {
+ ctx *common.AccessLogContext
+}
+
+type HTTP2Metrics struct {
+ connectionID uint64
+ hpackDecoder *hpack.Decoder
+
+ streams map[uint32]*HTTP2Streaming
+}
+
+type HTTP2Streaming struct {
+ reqHeader map[string]string
+ respHeader map[string]string
+ reqHeaderBuffer *buffer.Buffer
+ reqBodyBuffer *buffer.Buffer
+ isInResponse bool
+ status int
+ respHeaderBuffer *buffer.Buffer
+ respBodyBuffer *buffer.Buffer
+}
+
+func (r *HTTP2Protocol) GenerateConnection(connectionID uint64) ProtocolMetrics {
+ return &HTTP2Metrics{
+ connectionID: connectionID,
+ hpackDecoder: hpack.NewDecoder(4096, nil),
+ streams: make(map[uint32]*HTTP2Streaming),
+ }
+}
+
+func (r *HTTP2Protocol) Analyze(metrics ProtocolMetrics, buf *buffer.Buffer, helper *AnalyzeHelper) error {
+ http2Log.Debugf("ready to analyze HTTP/2 protocol data, connection ID: %d", metrics.(*HTTP2Metrics).connectionID)
+ http2Metrics := metrics.(*HTTP2Metrics)
+ buf.ResetForLoopReading()
+ for {
+ if !buf.PrepareForReading() {
+ return nil
+ }
+
+ startPosition := buf.Position()
+ header, err := http2.ReadFrameHeader(buf)
+ if err != nil {
+ http2Log.Debugf("failed to read frame header, %v", err)
+ if buf.SkipCurrentElement() {
+ break
+ }
+ continue
+ }
+ http2Log.Debugf("current reading buffer data id: %d, seq: %d", startPosition.DataID(), startPosition.Seq())
+
+ var protocolBreak bool
+ var result enums.ParseResult
+ switch header.Type {
+ case http2.FrameHeaders:
+ result, protocolBreak, _ = r.handleHeader(&header, startPosition, http2Metrics, buf)
+ case http2.FrameData:
+ result, protocolBreak, _ = r.handleData(&header, startPosition, http2Metrics, buf)
+ default:
+ tmp := make([]byte, header.Length)
+ if err := buf.ReadUntilBufferFull(tmp); err != nil {
+ if errors.Is(err, buffer.ErrNotComplete) {
+ result = enums.ParseResultSkipPackage
+ } else {
+ protocolBreak = true
+ }
+ } else {
+ result = enums.ParseResultSuccess
+ }
+ }
+
+ // if the protocol break, then stop the loop and notify the caller to skip analyze all data(just sending the detail)
+ if protocolBreak {
+ http2Log.Warnf("the HTTP/2 protocol break, maybe not tracing the connection from beginning, skip all data analyze in this connection, "+
+ "connection ID: %d", http2Metrics.connectionID)
+ helper.ProtocolBreak = true
+ break
+ }
+
+ finishReading := false
+ switch result {
+ case enums.ParseResultSuccess:
+ finishReading = buf.RemoveReadElements()
+ case enums.ParseResultSkipPackage:
+ finishReading = buf.SkipCurrentElement()
+ }
+
+ if finishReading {
+ break
+ }
+ }
+
+ return nil
+}
+
+func (r *HTTP2Protocol) handleHeader(header *http2.FrameHeader, startPos *buffer.Position,
+ metrics *HTTP2Metrics, buf *buffer.Buffer) (enums.ParseResult, bool, error) {
+ bytes := make([]byte, header.Length)
+ if err := buf.ReadUntilBufferFull(bytes); err != nil {
+ return enums.ParseResultSkipPackage, false, err
+ }
+ headerData, err := metrics.hpackDecoder.DecodeFull(bytes)
+ if err != nil {
+ // reading the header failure, maybe not tracing the connection from beginning
+ return enums.ParseResultSkipPackage, true, err
+ }
+ // saving stream
+ streaming := metrics.streams[header.StreamID]
+ headers := r.parseHeaders(headerData)
+ if streaming == nil {
+ streaming = &HTTP2Streaming{
+ reqHeader: headers,
+ respHeader: make(map[string]string),
+ reqHeaderBuffer: buf.Slice(true, startPos, buf.Position()),
+ }
+ metrics.streams[header.StreamID] = streaming
+ return enums.ParseResultSuccess, false, nil
+ }
+
+ status, contains := headers[":status"]
+ if contains {
+ streaming.isInResponse = true
+ code, err := strconv.ParseInt(status, 10, 64)
+ if err != nil {
+ log.Warnf("cannot parse status code: %s", status)
+ code = 200
+ }
+ streaming.status = int(code)
+ }
+
+ if !streaming.isInResponse {
+ r.appendHeaders(streaming.reqHeader, headers)
+ streaming.reqHeaderBuffer = buffer.CombineSlices(true, streaming.reqHeaderBuffer, buf.Slice(true, startPos, buf.Position()))
+ return enums.ParseResultSuccess, false, nil
+ }
+
+ r.appendHeaders(streaming.respHeader, headers)
+ streaming.respHeaderBuffer = buffer.CombineSlices(true, streaming.respHeaderBuffer, buf.Slice(true, startPos, buf.Position()))
+
+ // is end of stream and in the response
+ if header.Flags.Has(http2.FlagHeadersEndStream) {
+ // should be end of the stream and send to the protocol
+ r.handleWholeStream(streaming)
+ // delete streaming
+ delete(metrics.streams, header.StreamID)
+ }
+ return enums.ParseResultSuccess, false, nil
+}
+
+func (r *HTTP2Protocol) validateIsStreamOpenTooLong(metrics *HTTP2Metrics, id uint32, streaming *HTTP2Streaming) {
+ // if in the response mode or the request body is not nil, then skip
+ if streaming.isInResponse || streaming.reqBodyBuffer == nil {
+ return
+ }
+
+ // is the body sending too long, then split the stream
+ if time.Since(host.Time(streaming.respBodyBuffer.FirstSocketBuffer().StartTime())) > maxHTTP2StreamingTime {
+ http2Log.Infof("detect the HTTP/2 stream is too long, split the stream, connection ID: %d, stream ID: %d, headers: %v",
+ metrics.connectionID, id, streaming.reqHeader)
+
+ r.handleWholeStream(streaming)
+
+ // clean sent buffers
+ if streaming.reqBodyBuffer != nil {
+ streaming.reqBodyBuffer.Clean()
+ }
+ }
+}
+
+func (r *HTTP2Protocol) handleWholeStream(stream *HTTP2Streaming) {
+ detailEvents := make([]*events.SocketDetailEvent, 0)
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, stream.reqHeaderBuffer)
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, stream.reqBodyBuffer)
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, stream.respHeaderBuffer)
+ detailEvents = appendSocketDetailsFromBuffer(detailEvents, stream.respBodyBuffer)
+
+ if len(detailEvents) == 0 {
+ http2Log.Warnf("cannot found any detail events for HTTP/2 protocol, data id: %d-%d",
+ stream.reqHeaderBuffer.FirstSocketBuffer().DataID(), stream.respBodyBuffer.LastSocketBuffer().DataID())
+ return
+ }
+
+ forwarder.SendTransferProtocolEvent(r.ctx, detailEvents, &v3.AccessLogProtocolLogs{
+ Protocol: &v3.AccessLogProtocolLogs_Http{
+ Http: &v3.AccessLogHTTPProtocol{
+ StartTime: forwarder.BuildOffsetTimestamp(r.firstDetail(stream.reqBodyBuffer, detailEvents[0]).StartTime),
+ EndTime: forwarder.BuildOffsetTimestamp(detailEvents[len(detailEvents)-1].EndTime),
+ Version: v3.AccessLogHTTPProtocolVersion_HTTP2,
+ Request: &v3.AccessLogHTTPProtocolRequest{
+ Method: r.parseHTTPMethod(stream),
+ Path: stream.reqHeader[":path"],
+ SizeOfHeadersBytes: r.bufferSizeOfZero(stream.reqHeaderBuffer),
+ SizeOfBodyBytes: r.bufferSizeOfZero(stream.reqBodyBuffer),
+
+ Trace: analyzeTraceInfo(func(key string) string {
+ return stream.reqHeader[key]
+ }, http2Log),
+ },
+ Response: &v3.AccessLogHTTPProtocolResponse{
+ StatusCode: int32(stream.status),
+ SizeOfHeadersBytes: r.bufferSizeOfZero(stream.respHeaderBuffer),
+ SizeOfBodyBytes: r.bufferSizeOfZero(stream.respBodyBuffer),
+ },
+ },
+ },
+ })
+}
+
+func (r *HTTP2Protocol) parseHTTPMethod(streaming *HTTP2Streaming) v3.AccessLogHTTPProtocolRequestMethod {
+ method := streaming.reqHeader[":method"]
+ if method == "" {
+ return v3.AccessLogHTTPProtocolRequestMethod_Get
+ }
+
+ return transformHTTPMethod(strings.ToUpper(method))
+}
+
+func (r *HTTP2Protocol) firstDetail(buf *buffer.Buffer, def *events.SocketDetailEvent) *events.SocketDetailEvent {
+ if buf == nil || buf.Details() == nil || buf.Details().Len() == 0 {
+ return def
+ }
+ return buf.Details().Front().Value.(*events.SocketDetailEvent)
+}
+
+func (r *HTTP2Protocol) bufferSizeOfZero(buf *buffer.Buffer) uint64 {
+ if buf == nil {
+ return 0
+ }
+ return uint64(buf.DataSize())
+}
+
+func (r *HTTP2Protocol) appendHeaders(exist, needAppends map[string]string) {
+ for k, v := range needAppends {
+ exist[k] = v
+ }
+}
+
+func (r *HTTP2Protocol) handleData(header *http2.FrameHeader, startPos *buffer.Position,
+ metrics *HTTP2Metrics, buf *buffer.Buffer) (enums.ParseResult, bool, error) {
+ bytes := make([]byte, header.Length)
+ streaming := metrics.streams[header.StreamID]
+ if streaming == nil {
+ // cannot found the stream, maybe not tracing the connection from beginning
+ return enums.ParseResultSkipPackage, true, nil
+ }
+ if err := buf.ReadUntilBufferFull(bytes); err != nil {
+ return enums.ParseResultSkipPackage, false, err
+ }
+ if !streaming.isInResponse {
+ streaming.reqBodyBuffer = buffer.CombineSlices(true, streaming.reqBodyBuffer, buf.Slice(true, startPos, buf.Position()))
+ } else {
+ streaming.respBodyBuffer = buffer.CombineSlices(true, streaming.respBodyBuffer, buf.Slice(true, startPos, buf.Position()))
+ }
+
+ r.validateIsStreamOpenTooLong(metrics, header.StreamID, streaming)
+ return enums.ParseResultSuccess, false, nil
+}
+
+func (r *HTTP2Protocol) parseHeaders(headers []hpack.HeaderField) map[string]string {
+ result := make(map[string]string)
+ for _, header := range headers {
+ result[header.Name] = header.Value
+ }
+ return result
+}
diff --git a/pkg/accesslog/collector/protocols/protocol.go b/pkg/accesslog/collector/protocols/protocol.go
new file mode 100644
index 0000000..4c415c2
--- /dev/null
+++ b/pkg/accesslog/collector/protocols/protocol.go
@@ -0,0 +1,92 @@
+// 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 protocols
+
+import (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/tracing"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+var registeredProtocols = make(map[enums.ConnectionProtocol]func(ctx *common.AccessLogContext) Protocol)
+
+type ProtocolManager struct {
+ protocols map[enums.ConnectionProtocol]Protocol
+}
+
+func NewProtocolManager(ctx *common.AccessLogContext) *ProtocolManager {
+ protocols := make(map[enums.ConnectionProtocol]Protocol)
+ for protocol, generator := range registeredProtocols {
+ protocols[protocol] = generator(ctx)
+ }
+ return &ProtocolManager{protocols: protocols}
+}
+
+func (a *ProtocolManager) GetProtocol(protocol enums.ConnectionProtocol) Protocol {
+ return a.protocols[protocol]
+}
+
+type ProtocolMetrics interface {
+}
+
+type AnalyzeHelper struct {
+ ProtocolBreak bool
+}
+
+type Protocol interface {
+ GenerateConnection(connectionID uint64) ProtocolMetrics
+ Analyze(metrics ProtocolMetrics, buffer *buffer.Buffer, helper *AnalyzeHelper) error
+}
+
+func appendSocketDetailsFromBuffer(result []*events.SocketDetailEvent, buf *buffer.Buffer) []*events.SocketDetailEvent {
+ if buf.DetailLength() == 0 {
+ return result
+ }
+ for e := buf.Details().Front(); e != nil; e = e.Next() {
+ if len(result) > 0 && result[len(result)-1] == e.Value {
+ continue
+ }
+ result = append(result, e.Value.(*events.SocketDetailEvent))
+ }
+ return result
+}
+
+func analyzeTraceInfo(fetcher func(key string) string, protocolLog *logger.Logger) *v3.AccessLogTraceInfo {
+ context, err := tracing.AnalyzeTracingContext(func(key string) string {
+ return fetcher(key)
+ })
+ if err != nil {
+ protocolLog.Warnf("analyze tracing context error: %v", err)
+ return nil
+ }
+ if context == nil {
+ return nil
+ }
+
+ return &v3.AccessLogTraceInfo{
+ TraceId: context.TraceID(),
+ TraceSegmentId: context.TraceSegmentID(),
+ SpanId: context.SpanID(),
+ Provider: context.Provider().AccessLogType,
+ }
+}
diff --git a/pkg/accesslog/collector/protocols/queue.go b/pkg/accesslog/collector/protocols/queue.go
new file mode 100644
index 0000000..2c12c7a
--- /dev/null
+++ b/pkg/accesslog/collector/protocols/queue.go
@@ -0,0 +1,282 @@
+// 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 protocols
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+
+ "github.com/docker/go-units"
+
+ cmap "github.com/orcaman/concurrent-map"
+)
+
+var maxBufferExpireDuration = time.Minute
+
+var log = logger.GetLogger("accesslog", "collector", "protocols")
+
+type AnalyzeQueue struct {
+ context *common.AccessLogContext
+ eventQueue *btf.EventQueue
+ perCPUBuffer int64
+}
+
+func NewAnalyzeQueue(ctx *common.AccessLogContext) (*AnalyzeQueue, error) {
+ perCPUBufferSize, err := units.RAMInBytes(ctx.Config.ProtocolAnalyze.PerCPUBufferSize)
+ if err != nil {
+ return nil, err
+ }
+ if int(perCPUBufferSize) < os.Getpagesize() {
+ return nil, fmt.Errorf("the cpu buffer must bigger than %dB", os.Getpagesize())
+ }
+ if ctx.Config.ProtocolAnalyze.Parallels < 1 {
+ return nil, fmt.Errorf("the parallels cannot be small than 1")
+ }
+ if ctx.Config.ProtocolAnalyze.QueueSize < 1 {
+ return nil, fmt.Errorf("the queue size be small than 1")
+ }
+
+ return &AnalyzeQueue{
+ context: ctx,
+ perCPUBuffer: perCPUBufferSize,
+ eventQueue: btf.NewEventQueue(ctx.Config.ProtocolAnalyze.Parallels, ctx.Config.ProtocolAnalyze.QueueSize, func() btf.PartitionContext {
+ return NewPartitionContext(ctx)
+ }),
+ }, nil
+}
+
+func (q *AnalyzeQueue) Start(ctx context.Context) {
+ q.eventQueue.RegisterReceiver(q.context.BPF.SocketDetailDataQueue, int(q.perCPUBuffer), func() interface{} {
+ return &events.SocketDetailEvent{}
+ }, func(data interface{}) string {
+ return fmt.Sprintf("%d", data.(*events.SocketDetailEvent).GetConnectionID())
+ })
+ q.eventQueue.RegisterReceiver(q.context.BPF.SocketDataUploadEventQueue, int(q.perCPUBuffer), func() interface{} {
+ return &events.SocketDataUploadEvent{}
+ }, func(data interface{}) string {
+ return fmt.Sprintf("%d", data.(*events.SocketDataUploadEvent).ConnectionID)
+ })
+
+ q.eventQueue.Start(ctx, q.context.BPF.Linker)
+}
+
+type PartitionContext struct {
+ context *common.AccessLogContext
+ protocolMgr *ProtocolManager
+ connections cmap.ConcurrentMap
+
+ analyzeLocker sync.Mutex
+}
+
+func newPartitionConnection(protocolMgr *ProtocolManager, conID, randomID uint64, protocol enums.ConnectionProtocol) *PartitionConnection {
+ analyzer := protocolMgr.GetProtocol(protocol)
+ return &PartitionConnection{
+ connectionID: conID,
+ randomID: randomID,
+ dataBuffer: buffer.NewBuffer(),
+ protocol: protocol,
+ protocolAnalyzer: analyzer,
+ protocolMetrics: analyzer.GenerateConnection(conID),
+ }
+}
+
+func NewPartitionContext(ctx *common.AccessLogContext) *PartitionContext {
+ pc := &PartitionContext{
+ context: ctx,
+ protocolMgr: NewProtocolManager(ctx),
+ connections: cmap.New(),
+ }
+ ctx.ConnectionMgr.RegisterProcessor(pc)
+ return pc
+}
+
+func (p *PartitionContext) OnConnectionClose(event *events.SocketCloseEvent, closeCallback common.ConnectionProcessFinishCallback) {
+ conn, exist := p.connections.Get(p.buildConnectionKey(event.GetConnectionID(), event.GetRandomID()))
+ if !exist {
+ closeCallback()
+ return
+ }
+ connection := conn.(*PartitionConnection)
+ connection.closeCallback = closeCallback
+ connection.closed = true
+}
+
+func (p *PartitionContext) Start(ctx context.Context) {
+ // process events with interval
+ flushDuration, _ := time.ParseDuration(p.context.Config.Flush.Period)
+ timeTicker := time.NewTicker(flushDuration)
+ go func() {
+ for {
+ select {
+ case <-timeTicker.C:
+ // process event with interval
+ p.processEvents()
+ case <-ctx.Done():
+ timeTicker.Stop()
+ return
+ }
+ }
+ }()
+
+ // delete the expired events
+ expireTicker := time.NewTicker(maxBufferExpireDuration)
+ go func() {
+ for {
+ select {
+ case <-expireTicker.C:
+ p.processExpireEvents()
+ case <-ctx.Done():
+ expireTicker.Stop()
+ return
+ }
+ }
+ }()
+}
+
+func (p *PartitionContext) Consume(data interface{}) {
+ switch event := data.(type) {
+ case *events.SocketDetailEvent:
+ log.Debugf("receive the socket detail event, connection ID: %d, random ID: %d, data id: %d, function name: %s",
+ event.ConnectionID, event.RandomID, event.DataID0, event.FunctionName)
+ if event.Protocol == enums.ConnectionProtocolUnknown {
+ // if the connection protocol is unknown, we just needs to add this into the kernel log
+ forwarder.SendTransferNoProtocolEvent(p.context, event)
+ return
+ }
+ connection := p.getConnectionContext(event.GetConnectionID(), event.GetRandomID(), event.Protocol)
+ connection.appendDetail(p.context, event)
+ case *events.SocketDataUploadEvent:
+ log.Debugf("receive the socket data event, connection ID: %d, random ID: %d, data id: %d, sequence: %d, protocol: %d",
+ event.ConnectionID, event.RandomID, event.DataID0, event.Sequence0, event.Protocol)
+ connection := p.getConnectionContext(event.ConnectionID, event.RandomID, event.Protocol)
+ connection.appendData(event)
+ }
+}
+
+func (p *PartitionContext) getConnectionContext(connectionID, randomID uint64, protocol enums.ConnectionProtocol) *PartitionConnection {
+ conKey := p.buildConnectionKey(connectionID, randomID)
+ conn, exist := p.connections.Get(conKey)
+ if exist {
+ return conn.(*PartitionConnection)
+ }
+ result := newPartitionConnection(p.protocolMgr, connectionID, randomID, protocol)
+ p.connections.Set(conKey, result)
+ return result
+}
+
+func (p *PartitionContext) buildConnectionKey(conID, ranID uint64) string {
+ return fmt.Sprintf("%d_%d", conID, ranID)
+}
+
+func (p *PartitionContext) processEvents() {
+ // it could be triggered by interval or reach counter
+ // if any trigger bean locked, the other one just ignore process
+ if !p.analyzeLocker.TryLock() {
+ return
+ }
+ defer p.analyzeLocker.Unlock()
+
+ closedConnections := make([]string, 0)
+ p.connections.IterCb(func(conKey string, con interface{}) {
+ info := con.(*PartitionConnection)
+ p.processConnectionEvents(info)
+
+ // if the connection already closed and not contains any buffer data, then delete the connection
+ if info.closed && info.dataBuffer.DataLength() == 0 {
+ if info.closeCallback != nil {
+ info.closeCallback()
+ }
+ closedConnections = append(closedConnections, conKey)
+ }
+ })
+
+ for _, conKey := range closedConnections {
+ p.connections.Remove(conKey)
+ }
+}
+
+func (p *PartitionContext) processExpireEvents() {
+ // the expiry must be mutual exclusion with events processor
+ p.analyzeLocker.Lock()
+ defer p.analyzeLocker.Unlock()
+
+ p.connections.IterCb(func(_ string, con interface{}) {
+ p.processConnectionExpireEvents(con.(*PartitionConnection))
+ })
+}
+
+func (p *PartitionContext) processConnectionExpireEvents(connection *PartitionConnection) {
+ if c := connection.dataBuffer.DeleteExpireEvents(maxBufferExpireDuration); c > 0 {
+ log.Debugf("total removed %d expired socket data events", c)
+ }
+}
+
+func (p *PartitionContext) processConnectionEvents(connection *PartitionConnection) {
+ if connection.skipAllDataAnalyze {
+ return
+ }
+ helper := &AnalyzeHelper{}
+ if err := connection.protocolAnalyzer.Analyze(connection.protocolMetrics, connection.dataBuffer, helper); err != nil {
+ log.Warnf("failed to analyze the %s protocol data: %v", connection.protocol.String(), err)
+ }
+
+ if helper.ProtocolBreak {
+ // notify the connection manager to skip analyze all data(just sending the detail)
+ connection.skipAllDataAnalyze = true
+ p.context.ConnectionMgr.SkipAllDataAnalyze(connection.connectionID, connection.randomID)
+ connection.dataBuffer.Clean()
+ }
+}
+
+type PartitionConnection struct {
+ connectionID, randomID uint64
+ dataBuffer *buffer.Buffer
+ protocol enums.ConnectionProtocol
+ protocolAnalyzer Protocol
+ protocolMetrics ProtocolMetrics
+ closed bool
+ closeCallback common.ConnectionProcessFinishCallback
+ skipAllDataAnalyze bool
+}
+
+func (p *PartitionConnection) appendDetail(ctx *common.AccessLogContext, detail *events.SocketDetailEvent) {
+ if p.skipAllDataAnalyze {
+ // if the connection is already skip all data analyze, then just send the detail event
+ forwarder.SendTransferNoProtocolEvent(ctx, detail)
+ return
+ }
+ p.dataBuffer.AppendDetailEvent(detail)
+}
+
+func (p *PartitionConnection) appendData(data buffer.SocketDataBuffer) {
+ if p.skipAllDataAnalyze {
+ return
+ }
+ p.dataBuffer.AppendDataEvent(data)
+}
diff --git a/pkg/accesslog/collector/tls.go b/pkg/accesslog/collector/tls.go
new file mode 100644
index 0000000..f6ce7d9
--- /dev/null
+++ b/pkg/accesslog/collector/tls.go
@@ -0,0 +1,87 @@
+// 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 (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/module"
+ "github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/ssl"
+)
+
+var tlsLog = logger.GetLogger("access_log", "collector", "tls")
+
+var tlsCollectInstance = NewTLSCollector()
+
+type TLSCollector struct {
+ context *common.AccessLogContext
+ monitoredProcesses map[int32]bool
+ linker *btf.Linker
+}
+
+func NewTLSCollector() *TLSCollector {
+ return &TLSCollector{
+ monitoredProcesses: make(map[int32]bool),
+ linker: btf.NewLinker(),
+ }
+}
+
+func (c *TLSCollector) Start(_ *module.Manager, context *common.AccessLogContext) error {
+ c.context = context
+ context.ConnectionMgr.AddProcessListener(c)
+ return nil
+}
+
+func (c *TLSCollector) Stop() {
+ if err := c.linker.Close(); err != nil {
+ tlsLog.Warnf("close linker failure, error: %v", err)
+ }
+ c.monitoredProcesses = make(map[int32]bool)
+ c.linker = btf.NewLinker()
+}
+
+func (c *TLSCollector) OnNewProcessMonitoring(pid int32) {
+ if _, ok := c.monitoredProcesses[pid]; ok {
+ return
+ }
+ c.monitoredProcesses[pid] = true
+
+ register := ssl.NewSSLRegister(int(pid), c.linker)
+
+ register.OpenSSL(c.context.BPF.OpensslSymaddrMap, c.context.BPF.OpensslWrite, c.context.BPF.OpensslWriteRet,
+ c.context.BPF.OpensslRead, c.context.BPF.OpensslReadRet)
+
+ register.OpenSSL(nil, c.context.BPF.OpensslWrite, c.context.BPF.OpensslWriteRet,
+ c.context.BPF.OpensslRead, c.context.BPF.OpensslReadRet)
+
+ register.GoTLS(c.context.BPF.GoTlsArgsSymaddrMap, c.context.BPF.GoTlsWrite, c.context.BPF.GoTlsWriteRet,
+ c.context.BPF.GoTlsRead, c.context.BPF.GoTlsReadRet)
+
+ register.Node(nil, c.context.BPF.NodeTlsSymaddrMap, c.context.BPF.OpensslWrite, c.context.BPF.OpensslWriteRet,
+ c.context.BPF.OpensslRead, c.context.BPF.OpensslReadRet, c.context.BPF.NodeTlsRetSsl, c.context.BPF.NodeTlsWrap, c.context.BPF.NodeTlsWrapRet)
+
+ if err := register.Execute(); err != nil {
+ tlsLog.Errorf("register TLS failure, pid: %d, error: %v", pid, err)
+ delete(c.monitoredProcesses, pid)
+ }
+}
+
+func (c *TLSCollector) OnProcessRemoved(pid int32) {
+ delete(c.monitoredProcesses, pid)
+}
diff --git a/pkg/accesslog/collector/transfer.go b/pkg/accesslog/collector/transfer.go
new file mode 100644
index 0000000..3aa9f24
--- /dev/null
+++ b/pkg/accesslog/collector/transfer.go
@@ -0,0 +1,77 @@
+// 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 (
+ "github.com/apache/skywalking-rover/pkg/accesslog/collector/protocols"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/module"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/link"
+)
+
+var transferCollectInstance = NewTransferCollector()
+
+type TransferCollector struct {
+ protocolQueue *protocols.AnalyzeQueue
+}
+
+func NewTransferCollector() *TransferCollector {
+ return &TransferCollector{}
+}
+
+func (t *TransferCollector) Start(_ *module.Manager, context *common.AccessLogContext) error {
+ queue, err := protocols.NewAnalyzeQueue(context)
+ if err != nil {
+ return err
+ }
+
+ t.protocolQueue = queue
+ t.protocolQueue.Start(context.RuntimeContext)
+
+ context.BPF.AddTracePoint("skb", "skb_copy_datagram_iovec", context.BPF.TracepointSkbCopyDatagramIovec)
+
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"security_socket_sendmsg": context.BPF.SecuritySocketSendmsg})
+ context.BPF.AddLink(link.Kprobe, map[string]*ebpf.Program{"security_socket_recvmsg": context.BPF.SecuritySocketRecvmsg})
+
+ context.BPF.AddTracePoint("syscalls", "sys_enter_write", context.BPF.TracepointEnterWrite)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_write", context.BPF.TracepointExitWrite)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_read", context.BPF.TracepointEnterRead)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_read", context.BPF.TracepointExitRead)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_sendto", context.BPF.TracepointEnterSendto)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_sendto", context.BPF.TracepointExitSendto)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_writev", context.BPF.TracepointEnterWritev)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_writev", context.BPF.TracepointExitWritev)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_sendmsg", context.BPF.TracepointEnterSendmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_sendmsg", context.BPF.TracepointExitSendmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_sendmmsg", context.BPF.TracepointEnterSendmmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_sendmmsg", context.BPF.TracepointExitSendmmsg)
+ context.BPF.AddSysCall("recv", context.BPF.SysRecv, context.BPF.SysRecvRet)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_recvfrom", context.BPF.TracepointEnterRecvfrom)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_recvfrom", context.BPF.TracepointExitRecvfrom)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_recvmsg", context.BPF.TracepointEnterRecvmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_recvmsg", context.BPF.TracepointExitRecvmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_enter_recvmmsg", context.BPF.TracepointEnterRecvmmsg)
+ context.BPF.AddTracePoint("syscalls", "sys_exit_recvmmsg", context.BPF.TracepointExitRecvmmsg)
+
+ return nil
+}
+
+func (t *TransferCollector) Stop() {
+}
diff --git a/pkg/process/finders/base/process.go b/pkg/accesslog/common/accesslog.go
similarity index 56%
copy from pkg/process/finders/base/process.go
copy to pkg/accesslog/common/accesslog.go
index fc3b46f..63f4c76 100644
--- a/pkg/process/finders/base/process.go
+++ b/pkg/accesslog/common/accesslog.go
@@ -15,27 +15,18 @@
// specific language governing permissions and limitations
// under the License.
-package base
+package common
import (
- "github.com/shirou/gopsutil/process"
+ "context"
- "github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/tools/profiling"
+ "github.com/apache/skywalking-rover/pkg/accesslog/bpf"
)
-// DetectedProcess from the finder
-type DetectedProcess interface {
- // Pid of process in host
- Pid() int32
- // OriginalProcess is works for query the process data
- OriginalProcess() *process.Process
- // Entity of process, is related with backend entity
- Entity() *api.ProcessEntity
- // DetectType define the process find type
- DetectType() api.ProcessDetectType
- // ProfilingStat of process
- ProfilingStat() *profiling.Info
- // ExposePorts define which ports are exposed
- ExposePorts() []int
+type AccessLogContext struct {
+ BPF *bpf.Loader
+ Queue *Queue
+ ConnectionMgr *ConnectionManager
+ Config *Config
+ RuntimeContext context.Context
}
diff --git a/pkg/process/finders/base/process.go b/pkg/accesslog/common/config.go
similarity index 54%
rename from pkg/process/finders/base/process.go
rename to pkg/accesslog/common/config.go
index fc3b46f..de1bcee 100644
--- a/pkg/process/finders/base/process.go
+++ b/pkg/accesslog/common/config.go
@@ -15,27 +15,29 @@
// specific language governing permissions and limitations
// under the License.
-package base
+package common
-import (
- "github.com/shirou/gopsutil/process"
+import "github.com/apache/skywalking-rover/pkg/module"
- "github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/tools/profiling"
-)
+type Config struct {
+ module.Config
-// DetectedProcess from the finder
-type DetectedProcess interface {
- // Pid of process in host
- Pid() int32
- // OriginalProcess is works for query the process data
- OriginalProcess() *process.Process
- // Entity of process, is related with backend entity
- Entity() *api.ProcessEntity
- // DetectType define the process find type
- DetectType() api.ProcessDetectType
- // ProfilingStat of process
- ProfilingStat() *profiling.Info
- // ExposePorts define which ports are exposed
- ExposePorts() []int
+ Active bool `mapstructure:"active"`
+ Flush FlushConfig `mapstructure:"flush"`
+ ProtocolAnalyze ProtocolAnalyzeConfig `mapstructure:"protocol_analyze"`
+}
+
+type FlushConfig struct {
+ MaxCountOneStream int `mapstructure:"max_count"`
+ Period string `mapstructure:"period"`
+}
+
+type ProtocolAnalyzeConfig struct {
+ PerCPUBufferSize string `mapstructure:"per_cpu_buffer"`
+ Parallels int `mapstructure:"parallels"`
+ QueueSize int `mapstructure:"queue_size"`
+}
+
+func (c *Config) IsActive() bool {
+ return c.Active
}
diff --git a/pkg/accesslog/common/connection.go b/pkg/accesslog/common/connection.go
new file mode 100644
index 0000000..519f5e5
--- /dev/null
+++ b/pkg/accesslog/common/connection.go
@@ -0,0 +1,447 @@
+// 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 common
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/bpf"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/module"
+ "github.com/apache/skywalking-rover/pkg/process"
+ "github.com/apache/skywalking-rover/pkg/process/api"
+ "github.com/apache/skywalking-rover/pkg/process/finders/kubernetes"
+ "github.com/apache/skywalking-rover/pkg/tools"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/ip"
+
+ "github.com/cilium/ebpf"
+
+ cmap "github.com/orcaman/concurrent-map"
+
+ "k8s.io/apimachinery/pkg/util/cache"
+
+ v32 "skywalking.apache.org/repo/goapi/collect/common/v3"
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+const localAddressPairCacheTime = time.Hour * 6
+
+type addressProcessType int
+
+const (
+ addressProcessTypeUnknown addressProcessType = iota
+ addressProcessTypeLocal
+ addressProcessTypeKubernetes
+)
+
+type ConnectEventWithSocket struct {
+ *events.SocketConnectEvent
+ SocketPair *ip.SocketPair
+}
+
+type CloseEventWithNotify struct {
+ *events.SocketCloseEvent
+ allProcessorFinished bool
+}
+
+type ConnectionProcessFinishCallback func()
+
+type ConnectionProcessor interface {
+ OnConnectionClose(event *events.SocketCloseEvent, callback ConnectionProcessFinishCallback)
+}
+
+type ProcessListener interface {
+ OnNewProcessMonitoring(pid int32)
+ OnProcessRemoved(pid int32)
+}
+
+type ConnectionManager struct {
+ moduleMgr *module.Manager
+ processOP process.Operator
+ connections cmap.ConcurrentMap
+ // addressWithPid cache all local ip+port and pid mapping for match the process on the same host
+ // such as service mesh(process with envoy)
+ addressWithPid *cache.Expiring
+ // localIPWithPid cache all local monitoring process bind IP address
+ // for checking the remote address is local or not
+ localIPWithPid map[string]int32
+ // monitoringProcesses management all monitoring processes
+ monitoringProcesses map[int32][]api.ProcessInterface
+ // monitoring process map in BPF
+ processMonitorMap *ebpf.Map
+ activeConnectionMap *ebpf.Map
+
+ processors []ConnectionProcessor
+ processListeners []ProcessListener
+
+ // connection already close but the connection (protocols)log not build finished
+ allUnfinishedConnections map[string]*bool
+}
+
+func (c *ConnectionManager) RegisterProcessor(processor ConnectionProcessor) {
+ c.processors = append(c.processors, processor)
+}
+
+func (c *ConnectionManager) AddProcessListener(listener ProcessListener) {
+ c.processListeners = append(c.processListeners, listener)
+}
+
+type addressInfo struct {
+ pid uint32
+ processType addressProcessType
+}
+
+type ConnectionInfo struct {
+ RPCConnection *v3.AccessLogConnection
+ MarkDeletable bool
+ PID uint32
+}
+
+func NewConnectionManager(moduleMgr *module.Manager, bpfLoader *bpf.Loader) *ConnectionManager {
+ mgr := &ConnectionManager{
+ moduleMgr: moduleMgr,
+ processOP: moduleMgr.FindModule(process.ModuleName).(process.Operator),
+ connections: cmap.New(),
+ addressWithPid: cache.NewExpiring(),
+ localIPWithPid: make(map[string]int32),
+ monitoringProcesses: make(map[int32][]api.ProcessInterface),
+ processMonitorMap: bpfLoader.ProcessMonitorControl,
+ activeConnectionMap: bpfLoader.ActiveConnectionMap,
+ allUnfinishedConnections: make(map[string]*bool),
+ }
+ return mgr
+}
+
+func (c *ConnectionManager) Start() {
+ c.processOP.AddListener(c)
+}
+
+func (c *ConnectionManager) Stop() {
+ c.processOP.DeleteListener(c)
+}
+
+func (c *ConnectionManager) OnNewProcessExecuting(pid int32) {
+ // if the process should not be monitoring, then delete in the map
+ if !c.processOP.ShouldMonitor(pid) {
+ c.updateMonitorStatusForProcess(pid, false)
+ }
+}
+
+func (c *ConnectionManager) Find(event events.Event) *ConnectionInfo {
+ connectionKey := fmt.Sprintf("%d_%d", event.GetConnectionID(), event.GetRandomID())
+ data, exist := c.connections.Get(connectionKey)
+ if exist {
+ connection := data.(*ConnectionInfo)
+ c.connectionPostHandle(connection, event)
+ return connection
+ }
+ // is current is connected event, then getting the socket pair
+ if e, socket := getSocketPairFromConnectEvent(event); e != nil && socket != nil {
+ var localAddress, remoteAddress *v3.ConnectionAddress
+ localPID, _ := events.ParseConnectionID(event.GetConnectionID())
+ localAddress = c.buildAddressFromLocalKubernetesProcess(localPID, socket.SrcPort, addressProcessTypeKubernetes)
+ // trying to get the remote process if in the same host
+ remoteAddressInfo, ok := c.addressWithPid.Get(fmt.Sprintf("%s_%d", socket.DestIP, socket.DestPort))
+ if ok && remoteAddressInfo != nil {
+ address := remoteAddressInfo.(*addressInfo)
+ remoteAddress = c.buildAddressFromLocalKubernetesProcess(address.pid, socket.DestPort, address.processType)
+ } else {
+ remoteAddress = c.buildAddressFromRemote(socket.DestIP, socket.DestPort)
+ }
+ connection := c.buildConnection(e, socket, localAddress, remoteAddress)
+ c.connections.Set(connectionKey, connection)
+ return connection
+ }
+ return nil
+}
+
+func (c *ConnectionManager) connectionPostHandle(connection *ConnectionInfo, event events.Event) {
+ if connection == nil {
+ return
+ }
+ switch e := event.(type) {
+ case *CloseEventWithNotify:
+ if e.allProcessorFinished {
+ connection.MarkDeletable = true
+ } else {
+ // if not all processor finished, then add into the map
+ c.allUnfinishedConnections[fmt.Sprintf("%d_%d", event.GetConnectionID(), event.GetRandomID())] = &e.allProcessorFinished
+ }
+ case *events.SocketDetailEvent:
+ if e.SSL == 1 && connection.RPCConnection.TlsMode == v3.AccessLogConnectionTLSMode_Plain {
+ connection.RPCConnection.TlsMode = v3.AccessLogConnectionTLSMode_TLS
+ }
+ }
+}
+
+func (c *ConnectionManager) ProcessIsMonitor(pid uint32) bool {
+ return len(c.monitoringProcesses[int32(pid)]) > 0
+}
+
+func (c *ConnectionManager) buildConnection(event *events.SocketConnectEvent, socket *ip.SocketPair,
+ local, remote *v3.ConnectionAddress) *ConnectionInfo {
+ var role v32.DetectPoint
+ switch socket.Role {
+ case enums.ConnectionRoleClient:
+ role = v32.DetectPoint_client
+ case enums.ConnectionRoleServer:
+ role = v32.DetectPoint_server
+ }
+ connection := &v3.AccessLogConnection{
+ Local: local,
+ Remote: remote,
+ Role: role,
+ TlsMode: v3.AccessLogConnectionTLSMode_Plain,
+ }
+ return &ConnectionInfo{
+ RPCConnection: connection,
+ PID: event.PID,
+ }
+}
+
+func (c *ConnectionManager) buildAddressFromLocalKubernetesProcess(pid uint32, port uint16, _ addressProcessType) *v3.ConnectionAddress {
+ for _, pi := range c.monitoringProcesses[int32(pid)] {
+ if pi.DetectType() == api.Kubernetes {
+ entity := pi.Entity()
+ podContainer := pi.DetectProcess().(*kubernetes.Process).PodContainer()
+ return &v3.ConnectionAddress{
+ Address: &v3.ConnectionAddress_Kubernetes{
+ Kubernetes: &v3.KubernetesProcessAddress{
+ ServiceName: entity.ServiceName,
+ PodName: podContainer.Pod.Name,
+ ContainerName: podContainer.ContainerSpec.Name,
+ ProcessName: entity.ProcessName,
+ Port: int32(port),
+ },
+ },
+ }
+ }
+ }
+ return nil
+}
+
+func (c *ConnectionManager) buildAddressFromRemote(ipHost string, port uint16) *v3.ConnectionAddress {
+ return &v3.ConnectionAddress{
+ Address: &v3.ConnectionAddress_Ip{
+ Ip: &v3.IPAddress{
+ Host: ipHost,
+ Port: int32(port),
+ },
+ },
+ }
+}
+
+func (c *ConnectionManager) OnConnectionClose(event *events.SocketCloseEvent) *CloseEventWithNotify {
+ result := &CloseEventWithNotify{
+ SocketCloseEvent: event,
+ allProcessorFinished: false,
+ }
+ processCount := len(c.processors)
+ for _, l := range c.processors {
+ l.OnConnectionClose(event, func() {
+ processCount--
+ if processCount > 0 {
+ return
+ }
+ result.allProcessorFinished = true
+ })
+ }
+ return result
+}
+
+func (c *ConnectionManager) OnConnectEvent(event *events.SocketConnectEvent, pair *ip.SocketPair) {
+ // only adding the local ip port when remote is local address
+ if tp := c.isLocalTarget(pair); tp != addressProcessTypeUnknown {
+ c.addressWithPid.Set(fmt.Sprintf("%s_%d", pair.SrcIP, pair.SrcPort), &addressInfo{
+ pid: event.PID,
+ processType: tp,
+ }, localAddressPairCacheTime)
+ }
+}
+
+func (c *ConnectionManager) isLocalTarget(pair *ip.SocketPair) addressProcessType {
+ destIP := pair.DestIP
+ if tools.IsLocalHostAddress(destIP) {
+ return addressProcessTypeLocal
+ }
+ if _, exist := c.localIPWithPid[destIP]; exist {
+ return addressProcessTypeKubernetes
+ }
+ return addressProcessTypeUnknown
+}
+
+func (c *ConnectionManager) AddNewProcess(pid int32, entities []api.ProcessInterface) {
+ // adding monitoring process and IP addresses
+ c.monitoringProcesses[pid] = entities
+ c.updateMonitorStatusForProcess(pid, true)
+ for _, entity := range entities {
+ for _, host := range entity.ExposeHosts() {
+ c.localIPWithPid[host] = pid
+ }
+ }
+ for _, l := range c.processListeners {
+ l.OnNewProcessMonitoring(pid)
+ }
+}
+
+func (c *ConnectionManager) RemoveProcess(pid int32, entities []api.ProcessInterface) {
+ // delete monitoring process and IP addresses
+ delete(c.monitoringProcesses, pid)
+ c.updateMonitorStatusForProcess(pid, false)
+ for _, entity := range entities {
+ for _, host := range entity.ExposeHosts() {
+ delete(c.localIPWithPid, host)
+ }
+ }
+ for _, l := range c.processListeners {
+ l.OnProcessRemoved(pid)
+ }
+}
+
+func (c *ConnectionManager) RecheckAllProcesses(processes map[int32][]api.ProcessInterface) {
+ // checking the monitoring process
+ c.monitoringProcesses = processes
+ // for-each the existing monitored map, it should not be monitored, then remote it
+ iterate := c.processMonitorMap.Iterate()
+ processInBPF := make(map[int32]bool)
+ var pid uint32
+ var monitor uint32
+ for iterate.Next(&pid, &monitor) {
+ processInBPF[int32(pid)] = true
+ }
+
+ // make sure BPF and user space are consistent
+ for pid := range processInBPF {
+ if _, ok := c.monitoringProcesses[pid]; !ok {
+ c.updateMonitorStatusForProcess(pid, false)
+ for _, l := range c.processListeners {
+ l.OnProcessRemoved(pid)
+ }
+ }
+ }
+ for pid := range c.monitoringProcesses {
+ if _, ok := processInBPF[pid]; !ok {
+ c.updateMonitorStatusForProcess(pid, true)
+ for _, l := range c.processListeners {
+ l.OnNewProcessMonitoring(pid)
+ }
+ }
+ }
+
+ // update all IP addresses
+ result := make(map[string]int32)
+ for _, p := range processes {
+ for _, entity := range p {
+ for _, host := range entity.ExposeHosts() {
+ result[host] = entity.Pid()
+ }
+ }
+ }
+
+ c.localIPWithPid = result
+}
+
+func (c *ConnectionManager) updateMonitorStatusForProcess(pid int32, monitor bool) {
+ var err error
+ if monitor {
+ err = c.processMonitorMap.Update(pid, uint32(1), ebpf.UpdateAny)
+ } else {
+ err = c.processMonitorMap.Delete(pid)
+ }
+ if err != nil {
+ if !monitor && errors.Is(err, ebpf.ErrKeyNotExist) {
+ return
+ }
+ log.Warnf("failed to update the process %d monitor status to %t: %v", pid, monitor, err)
+ }
+}
+
+// OnBuildConnectionLogFinished notify the connection log build finished
+func (c *ConnectionManager) OnBuildConnectionLogFinished() {
+ // delete all connections which marked as deletable
+ // all deletable connection events been sent
+ deletableConnections := make([]string, 0)
+ c.connections.IterCb(func(key string, v interface{}) {
+ con, ok := v.(*ConnectionInfo)
+ if !ok || con == nil {
+ return
+ }
+ // already mark as deletable or process not monitoring
+ shouldDelete := con.MarkDeletable || len(c.monitoringProcesses[int32(con.PID)]) == 0
+
+ if shouldDelete {
+ deletableConnections = append(deletableConnections, key)
+ }
+ })
+
+ deleteFromUnfinished := make([]string, 0)
+ for conKey, processorFinished := range c.allUnfinishedConnections {
+ if *processorFinished {
+ deletableConnections = append(deletableConnections, conKey)
+ deleteFromUnfinished = append(deleteFromUnfinished, conKey)
+ }
+ }
+ for _, key := range deleteFromUnfinished {
+ delete(c.allUnfinishedConnections, key)
+ }
+
+ for _, key := range deletableConnections {
+ c.connections.Remove(key)
+ }
+}
+
+func (c *ConnectionManager) SkipAllDataAnalyze(conID, ranID uint64) {
+ var activateConn ActiveConnection
+ if err := c.activeConnectionMap.Lookup(conID, &activateConn); err != nil {
+ log.Warnf("cannot found the active connection: %d-%d", conID, ranID)
+ return
+ }
+ if activateConn.RandomID != ranID {
+ // make sure the connection is the same
+ return
+ }
+
+ activateConn.SkipDataUpload = 1
+ if err := c.activeConnectionMap.Update(conID, activateConn, ebpf.UpdateAny); err != nil {
+ log.Warnf("failed to update the active connection: %d-%d", conID, ranID)
+ }
+}
+
+func getSocketPairFromConnectEvent(event events.Event) (*events.SocketConnectEvent, *ip.SocketPair) {
+ if e, ok := event.(*ConnectEventWithSocket); ok {
+ return e.SocketConnectEvent, e.SocketPair
+ }
+ return nil, nil
+}
+
+type ActiveConnection struct {
+ RandomID uint64
+ PID uint32
+ SocketFD uint32
+ Role uint32
+ SocketFamily uint32
+ Protocol uint8
+ SSL uint8
+ SkipDataUpload uint8
+ // PAD for make sure it have same size when marshal data to the BPF
+ PAD0 uint8
+ PAD1 uint32
+}
diff --git a/pkg/accesslog/common/queue.go b/pkg/accesslog/common/queue.go
new file mode 100644
index 0000000..0cf15c8
--- /dev/null
+++ b/pkg/accesslog/common/queue.go
@@ -0,0 +1,141 @@
+// 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 common
+
+import (
+ "context"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/logger"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+var log = logger.GetLogger("access_log", "common")
+
+type KernelLog struct {
+ Type LogType
+ Event events.Event
+}
+
+type ProtocolLog struct {
+ KernelLogs []*events.SocketDetailEvent
+ Protocol *v3.AccessLogProtocolLogs
+}
+
+type Queue struct {
+ kernelLogs chan *KernelLog
+ protocolLogs chan *ProtocolLog
+
+ maxFlushCount int
+ period time.Duration
+ consumer QueueConsumer
+ consumeLock *sync.Mutex
+
+ dropKernelLogCount int64
+ dropProtocolLogCount int64
+}
+
+type QueueConsumer interface {
+ Consume(kernels chan *KernelLog, protocols chan *ProtocolLog)
+}
+
+func NewQueue(maxFlushCount int, period time.Duration, consumer QueueConsumer) *Queue {
+ return &Queue{
+ kernelLogs: make(chan *KernelLog, maxFlushCount*3),
+ protocolLogs: make(chan *ProtocolLog, maxFlushCount*3),
+ maxFlushCount: maxFlushCount,
+ period: period,
+ consumer: consumer,
+ consumeLock: &sync.Mutex{},
+ }
+}
+
+func (q *Queue) AppendKernelLog(tp LogType, event events.Event) {
+ select {
+ case q.kernelLogs <- &KernelLog{
+ Type: tp,
+ Event: event,
+ }:
+ default:
+ atomic.AddInt64(&q.dropKernelLogCount, 1)
+ return
+ }
+ q.consumeIfNeed()
+}
+
+func (q *Queue) AppendProtocolLog(kernelLogs []*events.SocketDetailEvent, protocol *v3.AccessLogProtocolLogs) {
+ select {
+ case q.protocolLogs <- &ProtocolLog{
+ KernelLogs: kernelLogs,
+ Protocol: protocol,
+ }:
+ default:
+ atomic.AddInt64(&q.dropProtocolLogCount, 1)
+ return
+ }
+ q.consumeIfNeed()
+}
+
+func (q *Queue) consumeIfNeed() {
+ if len(q.kernelLogs)+len(q.protocolLogs) >= q.maxFlushCount {
+ go q.consume()
+ }
+}
+
+func (q *Queue) Start(ctx context.Context) {
+ go func() {
+ timeTicker := time.NewTicker(q.period)
+ for {
+ select {
+ case <-timeTicker.C:
+ q.consume()
+ case <-ctx.Done():
+ timeTicker.Stop()
+ return
+ }
+ }
+ }()
+ go func() {
+ timeTicker := time.NewTicker(time.Second * 5)
+ for {
+ select {
+ case <-timeTicker.C:
+ if q.dropKernelLogCount > 0 || q.dropProtocolLogCount > 0 {
+ kernelLogCount := atomic.SwapInt64(&q.dropKernelLogCount, 0)
+ protocolLogCount := atomic.SwapInt64(&q.dropProtocolLogCount, 0)
+ log.Warnf("drop kernel log count: %d, drop protocol log count: %d", kernelLogCount, protocolLogCount)
+ }
+ case <-ctx.Done():
+ timeTicker.Stop()
+ return
+ }
+ }
+ }()
+}
+
+func (q *Queue) consume() {
+ if !q.consumeLock.TryLock() {
+ return
+ }
+ defer q.consumeLock.Unlock()
+ q.consumer.Consume(q.kernelLogs, q.protocolLogs)
+}
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/pkg/accesslog/common/type.go
similarity index 89%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to pkg/accesslog/common/type.go
index 555705c..53f288f 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/pkg/accesslog/common/type.go
@@ -15,11 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-package enums
+package common
-type ParseResult int
+type LogType int
const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
+ LogTypeConnect LogType = iota
+ LogTypeKernelTransfer
+ LogTypeClose
)
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/pkg/accesslog/events/base.go
similarity index 75%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to pkg/accesslog/events/base.go
index 555705c..89cc055 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/pkg/accesslog/events/base.go
@@ -15,11 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-package enums
+package events
-type ParseResult int
+import "time"
-const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
-)
+type Event interface {
+ GetConnectionID() uint64
+ GetRandomID() uint64
+ Timestamp() time.Time
+}
+
+func ParseConnectionID(connectionID uint64) (pid, socketFD uint32) {
+ return uint32(connectionID >> 32), uint32(connectionID & 0xFFFFFFFF)
+}
diff --git a/pkg/boot/register.go b/pkg/accesslog/events/close.go
similarity index 63%
copy from pkg/boot/register.go
copy to pkg/accesslog/events/close.go
index 8f0d64d..de24669 100644
--- a/pkg/boot/register.go
+++ b/pkg/accesslog/events/close.go
@@ -15,20 +15,33 @@
// specific language governing permissions and limitations
// under the License.
-package boot
+package events
import (
- "github.com/apache/skywalking-rover/pkg/core"
- "github.com/apache/skywalking-rover/pkg/logger"
- "github.com/apache/skywalking-rover/pkg/module"
- "github.com/apache/skywalking-rover/pkg/process"
- "github.com/apache/skywalking-rover/pkg/profiling"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/tools/host"
)
-func init() {
- // register all active module
- module.Register(logger.NewModule())
- module.Register(core.NewModule())
- module.Register(process.NewModule())
- module.Register(profiling.NewModule())
+type SocketCloseEvent struct {
+ ConnectionID uint64
+ RandomID uint64
+
+ StartTime uint64
+ EndTime uint64
+ PID uint32
+ SocketFD uint32
+ Success uint32
+}
+
+func (c *SocketCloseEvent) GetConnectionID() uint64 {
+ return c.ConnectionID
+}
+
+func (c *SocketCloseEvent) GetRandomID() uint64 {
+ return c.RandomID
+}
+
+func (c *SocketCloseEvent) Timestamp() time.Time {
+ return host.Time(c.StartTime)
}
diff --git a/pkg/accesslog/events/connect.go b/pkg/accesslog/events/connect.go
new file mode 100644
index 0000000..3e2a72b
--- /dev/null
+++ b/pkg/accesslog/events/connect.go
@@ -0,0 +1,59 @@
+// 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 events
+
+import (
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+)
+
+type SocketConnectEvent struct {
+ ConID uint64
+ RandomID uint64
+ StartTime uint64
+ EndTime uint64
+ PID uint32
+ SocketFD uint32
+ FuncName uint8
+ Role uint8
+ SocketFamily uint8
+ ConnectSuccess uint8
+ Pad0 uint32
+ RemoteAddrV4 uint32
+ RemoteAddrV6 [16]uint8
+ RemoteAddrPort uint32
+ LocalAddrV4 uint32
+ LocalAddrV6 [16]uint8
+ LocalAddrPort uint32
+ ConnTrackUpstreamPort uint32
+ ConnTrackUpstreamIPh uint64
+ ConnTrackUpstreamIPl uint64
+}
+
+func (c *SocketConnectEvent) GetConnectionID() uint64 {
+ return c.ConID
+}
+
+func (c *SocketConnectEvent) GetRandomID() uint64 {
+ return c.RandomID
+}
+
+func (c *SocketConnectEvent) Timestamp() time.Time {
+ return host.Time(c.StartTime)
+}
diff --git a/pkg/profiling/task/network/analyze/events/data.go b/pkg/accesslog/events/data.go
similarity index 53%
copy from pkg/profiling/task/network/analyze/events/data.go
copy to pkg/accesslog/events/data.go
index 46b0ae2..747ff9f 100644
--- a/pkg/profiling/task/network/analyze/events/data.go
+++ b/pkg/accesslog/events/data.go
@@ -19,42 +19,14 @@ package events
import (
"fmt"
-)
-type SocketDataBuffer interface {
- // GenerateConnectionID for identity the buffer belong which connection
- GenerateConnectionID() string
- // BufferData of the buffer
- BufferData() []byte
- // TotalSize of socket data, the data may exceed the size of the BufferData()
- TotalSize() uint64
- // Direction of the data, send or receive
- Direction() SocketDataDirection
- // BufferStartPosition the buffer start index
- BufferStartPosition() int
- // BufferLen the buffer data length
- BufferLen() int
- // DataID data id of the buffer
- DataID() uint64
- // DataSequence the data sequence under same data id
- DataSequence() int
- // IsStart this buffer is start of the same data id
- IsStart() bool
- // IsFinished this buffer is finish of the same data id
- IsFinished() bool
- // HaveReduceDataAfterChunk check have reduced data after current buffer
- HaveReduceDataAfterChunk() bool
-
- // StartTime the data start timestamp
- StartTime() uint64
- // EndTime the data end timestamp
- EndTime() uint64
-}
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+)
type SocketDataUploadEvent struct {
- Protocol ConnectionProtocol
+ Protocol enums.ConnectionProtocol
HaveReduce uint8
- Direction0 SocketDataDirection
+ Direction0 enums.SocketDataDirection
Finished uint8
Sequence0 uint16
DataLen uint16
@@ -87,7 +59,7 @@ func (s *SocketDataUploadEvent) EndTime() uint64 {
return s.EndTime0
}
-func (s *SocketDataUploadEvent) Direction() SocketDataDirection {
+func (s *SocketDataUploadEvent) Direction() enums.SocketDataDirection {
return s.Direction0
}
@@ -118,38 +90,3 @@ func (s *SocketDataUploadEvent) TotalSize() uint64 {
func (s *SocketDataUploadEvent) HaveReduceDataAfterChunk() bool {
return s.HaveReduce == 1
}
-
-type SocketDataEventLimited struct {
- SocketDataBuffer
- From int
- Size int
-}
-
-func (s *SocketDataEventLimited) BufferData() []byte {
- return s.SocketDataBuffer.BufferData()[s.From:s.Size]
-}
-
-func (s *SocketDataEventLimited) BufferLen() int {
- return s.Size - s.From
-}
-
-func (s *SocketDataEventLimited) BufferStartPosition() int {
- return s.From
-}
-
-type SocketDetailEvent struct {
- ConnectionID uint64
- RandomID uint64
- DataID uint64
- TotalPackageSize uint64
- IfIndex uint32
- PackageCount uint8
- FuncName SocketFunctionName
- RTTCount uint8
- Protocol ConnectionProtocol
- RTTTime uint32
-}
-
-func (s *SocketDetailEvent) GenerateConnectionID() string {
- return fmt.Sprintf("%d_%d", s.ConnectionID, s.RandomID)
-}
diff --git a/pkg/accesslog/events/detail.go b/pkg/accesslog/events/detail.go
new file mode 100644
index 0000000..ecb5f11
--- /dev/null
+++ b/pkg/accesslog/events/detail.go
@@ -0,0 +1,73 @@
+// 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 events
+
+import (
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+)
+
+type SocketDetailEvent struct {
+ ConnectionID uint64
+ RandomID uint64
+ DataID0 uint64
+
+ StartTime uint64
+ EndTime uint64
+
+ L4Duration uint32
+ L3Duration uint32
+ L3LocalDuration uint32
+ L3OutputDuration uint32
+ L3ResolveMacDuration uint32
+ L3NetFilterDuration uint32
+ L2Duration uint32
+ L2ReadySendDuration uint32
+ L2SendDuration uint32
+ L2PackageToQueueDuration uint32
+ L3TotalRcvDuration uint32
+ IfIndex uint32
+ L4PackageRcvFromQueueDuration uint64
+ L4TotalPackageSize uint64
+ L2EnterQueueCount uint8
+ L4PackageCount uint8
+ L4RetransmitPackageCount uint8
+ L3ResolveMacCount uint8
+ L3NetFilterCount uint8
+ FunctionName enums.SocketFunctionName
+ Protocol enums.ConnectionProtocol
+ SSL uint8
+}
+
+func (d *SocketDetailEvent) GetConnectionID() uint64 {
+ return d.ConnectionID
+}
+
+func (d *SocketDetailEvent) GetRandomID() uint64 {
+ return d.RandomID
+}
+
+func (d *SocketDetailEvent) Timestamp() time.Time {
+ return host.Time(d.StartTime)
+}
+
+func (d *SocketDetailEvent) DataID() uint64 {
+ return d.DataID0
+}
diff --git a/pkg/tools/host/network.go b/pkg/accesslog/forwarder/close.go
similarity index 50%
copy from pkg/tools/host/network.go
copy to pkg/accesslog/forwarder/close.go
index 34f24de..239c18d 100644
--- a/pkg/tools/host/network.go
+++ b/pkg/accesslog/forwarder/close.go
@@ -15,48 +15,32 @@
// specific language governing permissions and limitations
// under the License.
-package host
+package forwarder
import (
- "net"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
- "github.com/apache/skywalking-rover/pkg/logger"
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
)
-var interfaces map[int]*net.Interface
-var log = logger.GetLogger("tools", "host")
-
func init() {
- if err := refreshInterfaces(); err != nil {
- panic(err)
- }
+ registerKernelLogBuilder(common.LogTypeClose, closeLogBuilder)
}
-func NetworkName(ifindex int) string {
- i := interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- if e := refreshInterfaces(); e != nil {
- log.Warnf("error to refresh interfaces: %v", e)
- return ""
- }
- i = interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- return ""
+func SendCloseEvent(context *common.AccessLogContext, event *common.CloseEventWithNotify) {
+ context.Queue.AppendKernelLog(common.LogTypeClose, event)
}
-func refreshInterfaces() error {
- results, err := net.Interfaces()
- if err != nil {
- return err
- }
- tmp := make(map[int]*net.Interface)
- for _, interf := range results {
- tmp[interf.Index] = &interf
+func closeLogBuilder(event events.Event) *v3.AccessLogKernelLog {
+ closeEvent := event.(*common.CloseEventWithNotify)
+ closeOp := &v3.AccessLogKernelCloseOperation{}
+ closeOp.StartTime = BuildOffsetTimestamp(closeEvent.StartTime)
+ closeOp.EndTime = BuildOffsetTimestamp(closeEvent.EndTime)
+ closeOp.Success = closeEvent.Success == 1
+ return &v3.AccessLogKernelLog{
+ Operation: &v3.AccessLogKernelLog_Close{
+ Close: closeOp,
+ },
}
- interfaces = tmp
- return nil
}
diff --git a/pkg/accesslog/forwarder/connect.go b/pkg/accesslog/forwarder/connect.go
new file mode 100644
index 0000000..e57ac4e
--- /dev/null
+++ b/pkg/accesslog/forwarder/connect.go
@@ -0,0 +1,64 @@
+// 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 forwarder
+
+import (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/ip"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+func init() {
+ registerKernelLogBuilder(common.LogTypeConnect, connectLogBuilder)
+}
+
+func SendConnectEvent(context *common.AccessLogContext, event *events.SocketConnectEvent, socketPair *ip.SocketPair) {
+ context.Queue.AppendKernelLog(common.LogTypeConnect, &common.ConnectEventWithSocket{
+ SocketConnectEvent: event,
+ SocketPair: socketPair,
+ })
+}
+
+func connectLogBuilder(event events.Event) *v3.AccessLogKernelLog {
+ connectEvent := event.(*common.ConnectEventWithSocket)
+ switch connectEvent.FuncName {
+ case enums.SocketFunctionNameConnect:
+ return &v3.AccessLogKernelLog{
+ Operation: &v3.AccessLogKernelLog_Connect{
+ Connect: &v3.AccessLogKernelConnectOperation{
+ StartTime: BuildOffsetTimestamp(connectEvent.StartTime),
+ EndTime: BuildOffsetTimestamp(connectEvent.EndTime),
+ Success: connectEvent.ConnectSuccess == 1,
+ },
+ },
+ }
+ case enums.SocketFunctionNameAccept:
+ return &v3.AccessLogKernelLog{
+ Operation: &v3.AccessLogKernelLog_Accept{
+ Accept: &v3.AccessLogKernelAcceptOperation{
+ StartTime: BuildOffsetTimestamp(connectEvent.StartTime),
+ EndTime: BuildOffsetTimestamp(connectEvent.EndTime),
+ },
+ },
+ }
+ }
+ return nil
+}
diff --git a/pkg/tools/host/network.go b/pkg/accesslog/forwarder/forwarder.go
similarity index 51%
copy from pkg/tools/host/network.go
copy to pkg/accesslog/forwarder/forwarder.go
index 34f24de..3cac342 100644
--- a/pkg/tools/host/network.go
+++ b/pkg/accesslog/forwarder/forwarder.go
@@ -15,48 +15,37 @@
// specific language governing permissions and limitations
// under the License.
-package host
+package forwarder
import (
- "net"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
- "github.com/apache/skywalking-rover/pkg/logger"
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
)
-var interfaces map[int]*net.Interface
-var log = logger.GetLogger("tools", "host")
+type KernelLogBuilder func(data events.Event) *v3.AccessLogKernelLog
-func init() {
- if err := refreshInterfaces(); err != nil {
- panic(err)
- }
+var kernelLogBuilders = make([]KernelLogBuilder, 10)
+
+func registerKernelLogBuilder(tp common.LogType, builder KernelLogBuilder) {
+ kernelLogBuilders[tp] = builder
}
-func NetworkName(ifindex int) string {
- i := interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- if e := refreshInterfaces(); e != nil {
- log.Warnf("error to refresh interfaces: %v", e)
- return ""
+func BuildKernelLogFromEvent(tp common.LogType, event events.Event) *v3.AccessLogKernelLog {
+ builder := kernelLogBuilders[tp]
+ if builder == nil {
+ return nil
}
- i = interfaces[ifindex]
- if i != nil {
- return i.Name
- }
- return ""
+ return builder(event)
}
-func refreshInterfaces() error {
- results, err := net.Interfaces()
- if err != nil {
- return err
- }
- tmp := make(map[int]*net.Interface)
- for _, interf := range results {
- tmp[interf.Index] = &interf
+func BuildOffsetTimestamp(t uint64) *v3.EBPFTimestamp {
+ return &v3.EBPFTimestamp{
+ Timestamp: &v3.EBPFTimestamp_Offset{
+ Offset: &v3.EBPFOffsetTimestamp{
+ Offset: t,
+ },
+ },
}
- interfaces = tmp
- return nil
}
diff --git a/pkg/profiling/task/network/analyze/enums/protocol.go b/pkg/accesslog/forwarder/protocol.go
similarity index 66%
copy from pkg/profiling/task/network/analyze/enums/protocol.go
copy to pkg/accesslog/forwarder/protocol.go
index 555705c..dd158c8 100644
--- a/pkg/profiling/task/network/analyze/enums/protocol.go
+++ b/pkg/accesslog/forwarder/protocol.go
@@ -15,11 +15,15 @@
// specific language governing permissions and limitations
// under the License.
-package enums
+package forwarder
-type ParseResult int
+import (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
-const (
- ParseResultSuccess ParseResult = iota
- ParseResultSkipPackage
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
)
+
+func SendTransferProtocolEvent(context *common.AccessLogContext, kernelLogs []*events.SocketDetailEvent, protocolData *v3.AccessLogProtocolLogs) {
+ context.Queue.AppendProtocolLog(kernelLogs, protocolData)
+}
diff --git a/pkg/accesslog/forwarder/transfer.go b/pkg/accesslog/forwarder/transfer.go
new file mode 100644
index 0000000..882da0c
--- /dev/null
+++ b/pkg/accesslog/forwarder/transfer.go
@@ -0,0 +1,141 @@
+// 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 forwarder
+
+import (
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+func init() {
+ registerKernelLogBuilder(common.LogTypeKernelTransfer, kernelTransferLogBuilder)
+}
+
+func SendTransferNoProtocolEvent(context *common.AccessLogContext, event *events.SocketDetailEvent) {
+ context.Queue.AppendKernelLog(common.LogTypeKernelTransfer, event)
+}
+
+func kernelTransferLogBuilder(event events.Event) *v3.AccessLogKernelLog {
+ transferEvent := event.(*events.SocketDetailEvent)
+ // process the read or write
+ switch transferEvent.FunctionName.GetSocketOperationType() {
+ case enums.SocketOperationTypeWrite:
+ return &v3.AccessLogKernelLog{
+ Operation: &v3.AccessLogKernelLog_Write{
+ Write: &v3.AccessLogKernelWriteOperation{
+ StartTime: BuildOffsetTimestamp(transferEvent.StartTime),
+ EndTime: BuildOffsetTimestamp(transferEvent.EndTime),
+ Syscall: parseWriteSyscall(transferEvent.FunctionName),
+ L4Metrics: &v3.AccessLogKernelWriteL4Metrics{
+ TotalDuration: uint64(transferEvent.L4Duration),
+ TotalTransmitPackageCount: int64(transferEvent.L4PackageCount),
+ TotalRetransmitPackageCount: int64(transferEvent.L4RetransmitPackageCount),
+ TotalPackageSize: int64(transferEvent.L4TotalPackageSize),
+ },
+ L3Metrics: &v3.AccessLogKernelWriteL3Metrics{
+ TotalDuration: uint64(transferEvent.L3Duration),
+ TotalLocalDuration: uint64(transferEvent.L3LocalDuration),
+ TotalOutputDuration: uint64(transferEvent.L3OutputDuration),
+ TotalResolveMACCount: uint64(transferEvent.L3ResolveMacCount),
+ TotalResolveMACDuration: uint64(transferEvent.L3ResolveMacDuration),
+ TotalNetFilterCount: uint64(transferEvent.L3NetFilterCount),
+ TotalNetFilterDuration: uint64(transferEvent.L3NetFilterDuration),
+ },
+ L2Metrics: &v3.AccessLogKernelWriteL2Metrics{
+ TotalDuration: uint64(transferEvent.L2Duration),
+ Ifindex: transferEvent.IfIndex,
+ TotalEnterQueueBufferCount: uint64(transferEvent.L2EnterQueueCount),
+ TotalReadySendDuration: uint64(transferEvent.L2ReadySendDuration),
+ TotalNetDeviceSendDuration: uint64(transferEvent.L2SendDuration),
+ },
+ },
+ },
+ }
+ case enums.SocketOperationTypeRead:
+ return &v3.AccessLogKernelLog{
+ Operation: &v3.AccessLogKernelLog_Read{
+ Read: &v3.AccessLogKernelReadOperation{
+ StartTime: BuildOffsetTimestamp(transferEvent.StartTime),
+ EndTime: BuildOffsetTimestamp(transferEvent.EndTime),
+ Syscall: parseReadSyscall(transferEvent.FunctionName),
+ L2Metrics: &v3.AccessLogKernelReadL2Metrics{
+ Ifindex: transferEvent.IfIndex,
+ TotalPackageCount: uint32(transferEvent.L4PackageCount),
+ TotalPackageSize: transferEvent.L4TotalPackageSize,
+ TotalPackageToQueueDuration: uint64(transferEvent.L2PackageToQueueDuration),
+ TotalRcvPackageFromQueueDuration: transferEvent.L4PackageRcvFromQueueDuration,
+ },
+ L3Metrics: &v3.AccessLogKernelReadL3Metrics{
+ TotalDuration: uint64(transferEvent.L3Duration),
+ TotalRecvDuration: uint64(transferEvent.L3TotalRcvDuration),
+ TotalLocalDuration: uint64(transferEvent.L3LocalDuration),
+ TotalNetFilterCount: uint64(transferEvent.L3NetFilterCount),
+ TotalNetFilterDuration: uint64(transferEvent.L3NetFilterDuration),
+ },
+ L4Metrics: &v3.AccessLogKernelReadL4Metrics{
+ TotalDuration: uint64(transferEvent.L4Duration),
+ },
+ },
+ },
+ }
+ }
+ return nil
+}
+
+func parseReadSyscall(funcName enums.SocketFunctionName) v3.AccessLogKernelReadSyscall {
+ switch funcName {
+ case enums.SocketFunctionNameRead:
+ return v3.AccessLogKernelReadSyscall_Read
+ case enums.SocketFunctionNameReadv:
+ return v3.AccessLogKernelReadSyscall_Readv
+ case enums.SocketFunctionNameRecv:
+ return v3.AccessLogKernelReadSyscall_Recv
+ case enums.SocketFunctionNameRecvfrom:
+ return v3.AccessLogKernelReadSyscall_RecvFrom
+ case enums.SocketFunctionNameRecvMsg:
+ return v3.AccessLogKernelReadSyscall_RecvMsg
+ case enums.SocketFunctionNameRecvMMsg:
+ return v3.AccessLogKernelReadSyscall_RecvMmsg
+ default:
+ return v3.AccessLogKernelReadSyscall_Read
+ }
+}
+
+func parseWriteSyscall(funcName enums.SocketFunctionName) v3.AccessLogKernelWriteSyscall {
+ switch funcName {
+ case enums.SocketFunctionNameSend:
+ return v3.AccessLogKernelWriteSyscall_Send
+ case enums.SocketFunctionNameSendto:
+ return v3.AccessLogKernelWriteSyscall_SendTo
+ case enums.SocketFunctionNameSendMsg:
+ return v3.AccessLogKernelWriteSyscall_SendMsg
+ case enums.SocketFunctionNameSendMMSg:
+ return v3.AccessLogKernelWriteSyscall_SendMmsg
+ case enums.SocketFunctionNameSendFile:
+ return v3.AccessLogKernelWriteSyscall_SendFile
+ case enums.SocketFunctionNameWrite:
+ return v3.AccessLogKernelWriteSyscall_Write
+ case enums.SocketFunctionNameWritev:
+ return v3.AccessLogKernelWriteSyscall_Writev
+ default:
+ return v3.AccessLogKernelWriteSyscall_Write
+ }
+}
diff --git a/pkg/process/module.go b/pkg/accesslog/module.go
similarity index 53%
copy from pkg/process/module.go
copy to pkg/accesslog/module.go
index 769880e..ce1b03c 100644
--- a/pkg/process/module.go
+++ b/pkg/accesslog/module.go
@@ -15,28 +15,27 @@
// specific language governing permissions and limitations
// under the License.
-package process
+package accesslog
import (
"context"
- "time"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
"github.com/apache/skywalking-rover/pkg/core"
"github.com/apache/skywalking-rover/pkg/module"
- "github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/process/finders"
+ "github.com/apache/skywalking-rover/pkg/process"
)
-const ModuleName = "process_discovery"
+const ModuleName = "access_log"
type Module struct {
- config *Config
+ config *common.Config
- manager *finders.ProcessManager
+ runner *Runner
}
func NewModule() *Module {
- return &Module{config: &Config{}}
+ return &Module{config: &common.Config{}}
}
func (m *Module) Name() string {
@@ -44,7 +43,7 @@ func (m *Module) Name() string {
}
func (m *Module) RequiredModules() []string {
- return []string{core.ModuleName}
+ return []string{core.ModuleName, process.ModuleName}
}
func (m *Module) Config() module.ConfigInterface {
@@ -52,49 +51,24 @@ func (m *Module) Config() module.ConfigInterface {
}
func (m *Module) Start(ctx context.Context, mgr *module.Manager) error {
- period, err := time.ParseDuration(m.config.HeartbeatPeriod)
+ runner, err := NewRunner(mgr, m.config)
if err != nil {
return err
}
- processManager, err := finders.NewProcessManager(ctx, mgr, period, m.config.PropertiesReportPeriod,
- m.config.Scanner, m.config.Kubernetes)
+ err = runner.Start(ctx)
if err != nil {
return err
}
- m.manager = processManager
-
+ m.runner = runner
return nil
}
func (m *Module) NotifyStartSuccess() {
- // notify all finder to report processes
- m.manager.Start()
}
func (m *Module) Shutdown(ctx context.Context, mgr *module.Manager) error {
- return m.manager.Shutdown()
-}
-
-func (m *Module) GetAllProcesses() []api.ProcessInterface {
- return m.manager.GetAllProcesses()
-}
-
-func (m *Module) FindProcessByID(processID string) api.ProcessInterface {
- return m.manager.FindProcessByID(processID)
-}
-
-func (m *Module) FindAllRegisteredProcesses() []api.ProcessInterface {
- return m.manager.FindAllRegisteredProcesses()
-}
-
-func (m *Module) FindProcessByPID(pid int32) []api.ProcessInterface {
- return m.manager.FindProcessByPID(pid)
-}
-
-func (m *Module) AddListener(listener api.ProcessListener) {
- m.manager.AddListener(listener)
-}
-
-func (m *Module) DeleteListener(listener api.ProcessListener) {
- m.manager.DeleteListener(listener)
+ if m.runner != nil {
+ return m.runner.Stop()
+ }
+ return nil
}
diff --git a/pkg/accesslog/runner.go b/pkg/accesslog/runner.go
new file mode 100644
index 0000000..0571b4a
--- /dev/null
+++ b/pkg/accesslog/runner.go
@@ -0,0 +1,321 @@
+// 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 accesslog
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/apache/skywalking-rover/pkg/accesslog/bpf"
+ "github.com/apache/skywalking-rover/pkg/accesslog/collector"
+ "github.com/apache/skywalking-rover/pkg/accesslog/common"
+ "github.com/apache/skywalking-rover/pkg/accesslog/events"
+ "github.com/apache/skywalking-rover/pkg/accesslog/forwarder"
+ "github.com/apache/skywalking-rover/pkg/core"
+ "github.com/apache/skywalking-rover/pkg/core/backend"
+ "github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/module"
+ "github.com/apache/skywalking-rover/pkg/process"
+ "github.com/apache/skywalking-rover/pkg/tools/host"
+
+ v32 "skywalking.apache.org/repo/goapi/collect/common/v3"
+ v3 "skywalking.apache.org/repo/goapi/collect/ebpf/accesslog/v3"
+)
+
+const kernelAccessLogCacheTime = time.Minute * 5
+
+var log = logger.GetLogger("access_log", "runner")
+
+type Runner struct {
+ context *common.AccessLogContext
+ collectors []collector.Collector
+ mgr *module.Manager
+ backendOp backend.Operator
+ alsClient v3.EBPFAccessLogServiceClient
+ ctx context.Context
+}
+
+func NewRunner(mgr *module.Manager, config *common.Config) (*Runner, error) {
+ bpfLoader, err := bpf.NewLoader()
+ if err != nil {
+ return nil, err
+ }
+ flushDuration, err := time.ParseDuration(config.Flush.Period)
+ if err != nil {
+ return nil, fmt.Errorf("parse flush period error: %v", err)
+ }
+ backendOP := mgr.FindModule(core.ModuleName).(core.Operator).BackendOperator()
+ runner := &Runner{
+ context: &common.AccessLogContext{
+ BPF: bpfLoader,
+ Config: config,
+ ConnectionMgr: common.NewConnectionManager(mgr, bpfLoader),
+ },
+ collectors: collector.Collectors(),
+ mgr: mgr,
+ backendOp: backendOP,
+ alsClient: v3.NewEBPFAccessLogServiceClient(backendOP.GetConnection()),
+ }
+ runner.context.Queue = common.NewQueue(config.Flush.MaxCountOneStream, flushDuration, runner)
+ return runner, nil
+}
+
+func (r *Runner) Start(ctx context.Context) error {
+ r.ctx = ctx
+ r.context.RuntimeContext = ctx
+ r.context.Queue.Start(ctx)
+ r.context.ConnectionMgr.Start()
+ for _, c := range r.collectors {
+ err := c.Start(r.mgr, r.context)
+ if err != nil {
+ return err
+ }
+ }
+
+ if err := r.context.BPF.HasError(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (r *Runner) Consume(kernels chan *common.KernelLog, protocols chan *common.ProtocolLog) {
+ if r.backendOp.GetConnectionStatus() != backend.Connected {
+ log.Warnf("failure to connect to the backend, skip generating access log")
+ return
+ }
+
+ allLogs := r.buildConnectionLogs(kernels, protocols)
+ log.Debugf("ready to send access log, connection count: %d", len(allLogs))
+ if len(allLogs) == 0 {
+ return
+ }
+ if err := r.sendLogs(allLogs); err != nil {
+ log.Warnf("send access log failure: %v", err)
+ }
+}
+
+func (r *Runner) buildConnectionLogs(kernels chan *common.KernelLog, protocols chan *common.ProtocolLog) map[*common.ConnectionInfo]*connectionLogs {
+ result := make(map[*common.ConnectionInfo]*connectionLogs)
+ r.buildKernelLogs(kernels, result)
+ r.buildProtocolLogs(protocols, result)
+
+ r.context.ConnectionMgr.OnBuildConnectionLogFinished()
+ return result
+}
+
+func (r *Runner) buildKernelLogs(kernels chan *common.KernelLog, result map[*common.ConnectionInfo]*connectionLogs) {
+ delayAppends := make([]*common.KernelLog, 0)
+ for {
+ select {
+ case kernelLog := <-kernels:
+ connection, curLog, delay := r.buildKernelLog(kernelLog)
+ if connection != nil && curLog != nil {
+ logs, exist := result[connection]
+ if !exist {
+ logs = newConnectionLogs()
+ result[connection] = logs
+ }
+
+ logs.kernels = append(logs.kernels, curLog)
+ } else if delay {
+ delayAppends = append(delayAppends, kernelLog)
+ }
+ default:
+ for _, delayAppend := range delayAppends {
+ kernels <- delayAppend
+ }
+ return
+ }
+ }
+}
+
+func (r *Runner) buildProtocolLogs(protocols chan *common.ProtocolLog, result map[*common.ConnectionInfo]*connectionLogs) {
+ delayAppends := make([]*common.ProtocolLog, 0)
+ for {
+ select {
+ case protocolLog := <-protocols:
+ connection, kernelLogs, protocolLogs, delay := r.buildProtocolLog(protocolLog)
+ if connection != nil && len(kernelLogs) > 0 && protocolLogs != nil {
+ logs, exist := result[connection]
+ if !exist {
+ logs = newConnectionLogs()
+ result[connection] = logs
+ }
+ logs.protocols = append(logs.protocols, &connectionProtocolLog{
+ kernels: kernelLogs,
+ protocol: protocolLogs,
+ })
+ } else if delay {
+ delayAppends = append(delayAppends, protocolLog)
+ }
+ default:
+ for _, delayAppend := range delayAppends {
+ protocols <- delayAppend
+ }
+ return
+ }
+ }
+}
+
+func (r *Runner) sendLogs(allLogs map[*common.ConnectionInfo]*connectionLogs) error {
+ streaming, err := r.alsClient.Collect(r.ctx)
+ if err != nil {
+ return err
+ }
+
+ firstLog := true
+ firstConnection := true
+ for connection, logs := range allLogs {
+ if len(logs.kernels) > 0 {
+ r.sendLogToTheStream(streaming, r.buildAccessLogMessage(firstLog, firstConnection, connection, logs.kernels, nil))
+ firstLog, firstConnection = false, false
+ }
+ for _, protocolLog := range logs.protocols {
+ r.sendLogToTheStream(streaming, r.buildAccessLogMessage(firstLog, firstConnection, connection, protocolLog.kernels, protocolLog.protocol))
+ firstLog, firstConnection = false, false
+ }
+
+ firstConnection = true
+ }
+
+ if _, err := streaming.CloseAndRecv(); err != nil {
+ log.Warnf("closing the access log streaming error: %v", err)
+ }
+ return nil
+}
+
+func (r *Runner) sendLogToTheStream(streaming v3.EBPFAccessLogService_CollectClient, logMsg *v3.EBPFAccessLogMessage) {
+ if err := streaming.Send(logMsg); err != nil {
+ log.Warnf("send access log failure: %v", err)
+ }
+}
+
+func (r *Runner) buildAccessLogMessage(firstLog, firstConnection bool, conn *common.ConnectionInfo,
+ kernelLogs []*v3.AccessLogKernelLog, protocolLog *v3.AccessLogProtocolLogs) *v3.EBPFAccessLogMessage {
+ var rpcCon *v3.AccessLogConnection
+ if firstConnection {
+ rpcCon = conn.RPCConnection
+ }
+ return &v3.EBPFAccessLogMessage{
+ Node: r.BuildNodeInfo(firstLog),
+ Connection: rpcCon,
+ KernelLogs: kernelLogs,
+ ProtocolLog: protocolLog,
+ }
+}
+
+func (r *Runner) BuildNodeInfo(needs bool) *v3.EBPFAccessLogNodeInfo {
+ if !needs {
+ return nil
+ }
+ netInterfaces := make([]*v3.EBPFAccessLogNodeNetInterface, 0)
+ for i, n := range host.AllNetworkInterfaces() {
+ netInterfaces = append(netInterfaces, &v3.EBPFAccessLogNodeNetInterface{
+ Index: int32(i),
+ Mtu: int32(n.MTU),
+ Name: n.Name,
+ })
+ }
+ return &v3.EBPFAccessLogNodeInfo{
+ Name: r.mgr.FindModule(process.ModuleName).(process.K8sOperator).NodeName(),
+ NetInterfaces: netInterfaces,
+ BootTime: r.convertTimeToInstant(host.BootTime),
+ }
+}
+
+func (r *Runner) convertTimeToInstant(t time.Time) *v32.Instant {
+ return &v32.Instant{
+ Seconds: t.Unix(),
+ Nanos: int32(t.Nanosecond()),
+ }
+}
+
+func (r *Runner) buildProtocolLog(protocolLog *common.ProtocolLog) (*common.ConnectionInfo,
+ []*v3.AccessLogKernelLog, *v3.AccessLogProtocolLogs, bool) {
+ if len(protocolLog.KernelLogs) == 0 {
+ return nil, nil, nil, false
+ }
+ firstKernelLog := protocolLog.KernelLogs[0]
+ pid, _ := events.ParseConnectionID(firstKernelLog.GetConnectionID())
+ // if the process not monitoring, then ignore it
+ if !r.context.ConnectionMgr.ProcessIsMonitor(pid) {
+ return nil, nil, nil, false
+ }
+ connection := r.context.ConnectionMgr.Find(firstKernelLog)
+ if connection == nil {
+ // if the connection cannot be found, it means that the connection have not been established
+ // just re-add into the queue for checking in the next period
+ if time.Since(firstKernelLog.Timestamp()) > kernelAccessLogCacheTime {
+ return nil, nil, nil, false
+ }
+ return nil, nil, nil, true
+ }
+ kernelLogs := make([]*v3.AccessLogKernelLog, 0)
+ for _, kl := range protocolLog.KernelLogs {
+ event := forwarder.BuildKernelLogFromEvent(common.LogTypeKernelTransfer, kl)
+ if event == nil {
+ continue
+ }
+ kernelLogs = append(kernelLogs, event)
+ }
+
+ return connection, kernelLogs, protocolLog.Protocol, false
+}
+
+func (r *Runner) buildKernelLog(kernelLog *common.KernelLog) (*common.ConnectionInfo, *v3.AccessLogKernelLog, bool) {
+ pid, _ := events.ParseConnectionID(kernelLog.Event.GetConnectionID())
+ // if the process not monitoring, then ignore it
+ if !r.context.ConnectionMgr.ProcessIsMonitor(pid) {
+ return nil, nil, false
+ }
+ connection := r.context.ConnectionMgr.Find(kernelLog.Event)
+ if connection == nil {
+ // if the connection cannot be found, it means that the connection have not been established
+ // just re-add into the queue for checking in the next period
+ if time.Since(kernelLog.Event.Timestamp()) > kernelAccessLogCacheTime {
+ return nil, nil, false
+ }
+ return nil, nil, true
+ }
+ event := forwarder.BuildKernelLogFromEvent(kernelLog.Type, kernelLog.Event)
+ return connection, event, false
+}
+
+func (r *Runner) Stop() error {
+ r.context.ConnectionMgr.Stop()
+ return nil
+}
+
+type connectionLogs struct {
+ kernels []*v3.AccessLogKernelLog
+ protocols []*connectionProtocolLog
+}
+
+type connectionProtocolLog struct {
+ kernels []*v3.AccessLogKernelLog
+ protocol *v3.AccessLogProtocolLogs
+}
+
+func newConnectionLogs() *connectionLogs {
+ return &connectionLogs{
+ kernels: make([]*v3.AccessLogKernelLog, 0),
+ protocols: make([]*connectionProtocolLog, 0),
+ }
+}
diff --git a/pkg/boot/register.go b/pkg/boot/register.go
index 8f0d64d..f383c90 100644
--- a/pkg/boot/register.go
+++ b/pkg/boot/register.go
@@ -18,6 +18,7 @@
package boot
import (
+ "github.com/apache/skywalking-rover/pkg/accesslog"
"github.com/apache/skywalking-rover/pkg/core"
"github.com/apache/skywalking-rover/pkg/logger"
"github.com/apache/skywalking-rover/pkg/module"
@@ -31,4 +32,5 @@ func init() {
module.Register(core.NewModule())
module.Register(process.NewModule())
module.Register(profiling.NewModule())
+ module.Register(accesslog.NewModule())
}
diff --git a/pkg/process/api.go b/pkg/process/api.go
index 9f7bdb3..b84453b 100644
--- a/pkg/process/api.go
+++ b/pkg/process/api.go
@@ -30,4 +30,11 @@ type Operator interface {
AddListener(listener api.ProcessListener)
// DeleteListener delete the process listener
DeleteListener(listener api.ProcessListener)
+ // ShouldMonitor check the process should be monitored
+ ShouldMonitor(pid int32) bool
+}
+
+type K8sOperator interface {
+ // NodeName get the node name
+ NodeName() string
}
diff --git a/pkg/process/api/process.go b/pkg/process/api/process.go
index fca705e..ad77644 100644
--- a/pkg/process/api/process.go
+++ b/pkg/process/api/process.go
@@ -58,11 +58,33 @@ type ProcessInterface interface {
ExeName() (string, error)
// OriginalProcess from process library
OriginalProcess() *process.Process
+ // DetectProcess from finder
+ DetectProcess() DetectedProcess
// PortIsExpose check the port is exposed
PortIsExpose(port int) bool
// DetectNewExposePort add a new detected expose port
DetectNewExposePort(port int)
+ // ExposeHosts get all exposed hosts
+ ExposeHosts() []string
+}
+
+// DetectedProcess from the finder
+type DetectedProcess interface {
+ // Pid of process in host
+ Pid() int32
+ // OriginalProcess is works for query the process data
+ OriginalProcess() *process.Process
+ // Entity of process, is related with backend entity
+ Entity() *ProcessEntity
+ // DetectType define the process find type
+ DetectType() ProcessDetectType
+ // ProfilingStat of process
+ ProfilingStat() *profiling.Info
+ // ExposePorts define which ports are exposed
+ ExposePorts() []int
+ // ExposeHosts define which hosts are exposed
+ ExposeHosts() []string
}
// ProcessEntity is related to backend entity concept
diff --git a/pkg/process/finders/base/finder.go b/pkg/process/finders/base/finder.go
index d1edefa..d4ba8b1 100644
--- a/pkg/process/finders/base/finder.go
+++ b/pkg/process/finders/base/finder.go
@@ -42,20 +42,25 @@ type ProcessFinder interface {
// DetectType of Process is detecting
DetectType() api.ProcessDetectType
+ // ShouldMonitor validate the process needs to be monitored, if true, then add it into the storage
+ ShouldMonitor(pid int32) bool
+
// ValidateProcessIsSame between two same finder process
- ValidateProcessIsSame(p1, p2 DetectedProcess) bool
+ ValidateProcessIsSame(p1, p2 api.DetectedProcess) bool
// BuildEBPFProcess is transform the process entity as backend protocol data
- BuildEBPFProcess(ctx *BuildEBPFProcessContext, process DetectedProcess) *v3.EBPFProcessProperties
+ BuildEBPFProcess(ctx *BuildEBPFProcessContext, process api.DetectedProcess) *v3.EBPFProcessProperties
// BuildNecessaryProperties is getting minimize necessary properties when keep alive
- BuildNecessaryProperties(process DetectedProcess) []*commonv3.KeyStringValuePair
+ BuildNecessaryProperties(process api.DetectedProcess) []*commonv3.KeyStringValuePair
// ParseProcessId is means how to read the process id receive from backend
- ParseProcessID(process DetectedProcess, downstream *v3.EBPFProcessDownstream) string
+ ParseProcessID(process api.DetectedProcess, downstream *v3.EBPFProcessDownstream) string
}
// ProcessManager is an API work for help ProcessFinder synchronized process with backend
type ProcessManager interface {
GetModuleManager() *module.Manager
// SyncAllProcessInFinder is mean synchronized all processes data from current ProcessFinder
- SyncAllProcessInFinder(processes []DetectedProcess)
+ SyncAllProcessInFinder(processes []api.DetectedProcess)
+ // AddDetectedProcess only add the specific processes
+ AddDetectedProcess(processes []api.DetectedProcess)
}
diff --git a/pkg/process/finders/context.go b/pkg/process/finders/context.go
index b1760a4..1ed5cad 100644
--- a/pkg/process/finders/context.go
+++ b/pkg/process/finders/context.go
@@ -19,7 +19,6 @@ package finders
import (
"github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/process/finders/base"
"github.com/apache/skywalking-rover/pkg/tools/profiling"
"github.com/shirou/gopsutil/process"
@@ -45,7 +44,7 @@ type ProcessContext struct {
syncStatus ProcessUploadStatus
// detectProcess from finder
- detectProcess base.DetectedProcess
+ detectProcess api.DetectedProcess
detectType api.ProcessDetectType
// cache
@@ -73,6 +72,10 @@ func (p *ProcessContext) ProfilingStat() *profiling.Info {
return p.detectProcess.ProfilingStat()
}
+func (p *ProcessContext) DetectProcess() api.DetectedProcess {
+ return p.detectProcess
+}
+
func (p *ProcessContext) ExeName() (string, error) {
if p.exeName == "" {
exe, err := p.detectProcess.OriginalProcess().Name()
@@ -95,3 +98,7 @@ func (p *ProcessContext) PortIsExpose(port int) bool {
func (p *ProcessContext) DetectNewExposePort(port int) {
p.exposedPorts[port] = true
}
+
+func (p *ProcessContext) ExposeHosts() []string {
+ return p.detectProcess.ExposeHosts()
+}
diff --git a/pkg/process/finders/kubernetes/finder.go b/pkg/process/finders/kubernetes/finder.go
index c39ff75..14522d6 100644
--- a/pkg/process/finders/kubernetes/finder.go
+++ b/pkg/process/finders/kubernetes/finder.go
@@ -155,54 +155,60 @@ func (f *ProcessFinder) analyzeProcesses() error {
return err
}
- result := make([]base.DetectedProcess, 0)
+ result := make([]api.DetectedProcess, 0)
for _, p := range processes {
- createTime, err := p.CreateTime()
- if err != nil {
- continue
- }
- processCahceKey := fmt.Sprintf("%d_%d", p.Pid, createTime)
- cachedProcesses, exist := f.processCache.Get(processCahceKey)
- if exist {
- for _, pro := range cachedProcesses.([]*Process) {
- result = append(result, pro)
- }
- continue
- }
+ result, _ = f.buildProcess(p, result, containers)
+ }
- cgroups, err := f.getProcessCGroup(p.Pid)
- if err != nil {
- continue
- }
+ if len(result) > 0 {
+ f.manager.SyncAllProcessInFinder(result)
+ }
+ return nil
+}
- var c *PodContainer
- for _, cgroup := range cgroups {
- if cc := containers[cgroup]; cc != nil {
- c = cc
- break
- }
- }
- if c == nil {
- continue
+func (f *ProcessFinder) buildProcess(p *process.Process, detectedProcesses []api.DetectedProcess,
+ containers map[string]*PodContainer) ([]api.DetectedProcess, bool) {
+ createTime, err := p.CreateTime()
+ if err != nil {
+ return detectedProcesses, false
+ }
+ processCahceKey := fmt.Sprintf("%d_%d", p.Pid, createTime)
+ cachedProcesses, exist := f.processCache.Get(processCahceKey)
+ if exist {
+ for _, pro := range cachedProcesses.([]*Process) {
+ detectedProcesses = append(detectedProcesses, pro)
}
+ return detectedProcesses, false
+ }
- // find process builder
- ps, err := f.buildProcesses(p, c)
- if err != nil {
- log.Warnf("find process builder error for pid: %d, err: %v", p.Pid, err)
- continue
- }
+ cgroups, err := f.getProcessCGroup(p.Pid)
+ if err != nil {
+ return detectedProcesses, false
+ }
- for _, pro := range ps {
- result = append(result, pro)
+ var c *PodContainer
+ for _, cgroup := range cgroups {
+ if cc := containers[cgroup]; cc != nil {
+ c = cc
+ break
}
- f.processCache.Add(processCahceKey, ps)
+ }
+ if c == nil {
+ return detectedProcesses, false
}
- if len(result) > 0 {
- f.manager.SyncAllProcessInFinder(result)
+ // find process builder
+ ps, err := f.buildProcesses(p, c)
+ if err != nil {
+ log.Warnf("find process builder error for pid: %d, err: %v", p.Pid, err)
+ return detectedProcesses, false
}
- return nil
+
+ for _, pro := range ps {
+ detectedProcesses = append(detectedProcesses, pro)
+ }
+ f.processCache.Add(processCahceKey, ps)
+ return detectedProcesses, true
}
func (f *ProcessFinder) buildProcesses(p *process.Process, pc *PodContainer) ([]*Process, error) {
@@ -299,13 +305,13 @@ func (f *ProcessFinder) DetectType() api.ProcessDetectType {
return api.Kubernetes
}
-func (f *ProcessFinder) ValidateProcessIsSame(p1, p2 base.DetectedProcess) bool {
+func (f *ProcessFinder) ValidateProcessIsSame(p1, p2 api.DetectedProcess) bool {
k1 := p1.(*Process)
k2 := p2.(*Process)
return p1.Pid() == p2.Pid() && k1.cmd == k2.cmd && p1.Entity().SameWith(p2.Entity())
}
-func (f *ProcessFinder) BuildNecessaryProperties(ps base.DetectedProcess) []*commonv3.KeyStringValuePair {
+func (f *ProcessFinder) BuildNecessaryProperties(ps api.DetectedProcess) []*commonv3.KeyStringValuePair {
return []*commonv3.KeyStringValuePair{
{
Key: "support_ebpf_profiling",
@@ -314,7 +320,7 @@ func (f *ProcessFinder) BuildNecessaryProperties(ps base.DetectedProcess) []*com
}
}
-func (f *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps base.DetectedProcess) *v3.EBPFProcessProperties {
+func (f *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps api.DetectedProcess) *v3.EBPFProcessProperties {
k8sProcess := &v3.EBPFKubernetesProcessMetadata{}
k8sProcess.Pid = ps.Pid()
k8sProcess.Entity = &v3.EBPFProcessEntityMetadata{
@@ -357,7 +363,7 @@ func (f *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps b
return properties
}
-func (f *ProcessFinder) ParseProcessID(ps base.DetectedProcess, downstream *v3.EBPFProcessDownstream) string {
+func (f *ProcessFinder) ParseProcessID(ps api.DetectedProcess, downstream *v3.EBPFProcessDownstream) string {
if downstream.GetK8SProcess() == nil {
return ""
}
@@ -367,3 +373,17 @@ func (f *ProcessFinder) ParseProcessID(ps base.DetectedProcess, downstream *v3.E
}
return ""
}
+
+func (f *ProcessFinder) ShouldMonitor(pid int32) bool {
+ newProcess, err := process.NewProcess(pid)
+ if err != nil {
+ return false
+ }
+ // analyze the process needs to be monitored
+ processes, monitor := f.buildProcess(newProcess, nil, f.registry.BuildPodContainers())
+ if !monitor || len(processes) == 0 {
+ return false
+ }
+ f.manager.AddDetectedProcess(processes)
+ return true
+}
diff --git a/pkg/process/finders/kubernetes/process.go b/pkg/process/finders/kubernetes/process.go
index 5bae8ed..9879258 100644
--- a/pkg/process/finders/kubernetes/process.go
+++ b/pkg/process/finders/kubernetes/process.go
@@ -95,3 +95,11 @@ func (p *Process) ExposePorts() []int {
return result
}
+
+func (p *Process) ExposeHosts() []string {
+ result := make([]string, 0)
+ for _, ip := range p.podContainer.Pod.Status.PodIPs {
+ result = append(result, ip.IP)
+ }
+ return result
+}
diff --git a/pkg/process/finders/manager.go b/pkg/process/finders/manager.go
index 8c59368..03ecf69 100644
--- a/pkg/process/finders/manager.go
+++ b/pkg/process/finders/manager.go
@@ -48,6 +48,8 @@ type ProcessManager struct {
type ProcessManagerWithFinder struct {
*ProcessManager
finderType api.ProcessDetectType
+
+ lastSync []api.DetectedProcess
}
func NewProcessManager(ctx context.Context, moduleManager *module.Manager,
@@ -117,10 +119,23 @@ func (p *ProcessManagerWithFinder) GetModuleManager() *module.Manager {
return p.moduleManager
}
-func (p *ProcessManagerWithFinder) SyncAllProcessInFinder(processes []base.DetectedProcess) {
+func (p *ProcessManagerWithFinder) SyncAllProcessInFinder(processes []api.DetectedProcess) {
p.storage.SyncAllProcessInFinder(p.finderType, processes)
}
+func (p *ProcessManagerWithFinder) AddDetectedProcess(processes []api.DetectedProcess) {
+ if len(p.lastSync) == 0 {
+ p.SyncAllProcessInFinder(processes)
+ p.lastSync = processes
+ return
+ }
+ // fetch existing process, add the new processes, finally, re-sync
+ detectedProcesses := make([]api.DetectedProcess, len(processes)+len(p.lastSync))
+ detectedProcesses = append(detectedProcesses, p.lastSync...)
+ detectedProcesses = append(detectedProcesses, processes...)
+ p.SyncAllProcessInFinder(detectedProcesses)
+}
+
func (m *ProcessManager) GetAllProcesses() []api.ProcessInterface {
return m.storage.GetAllProcesses()
}
@@ -144,3 +159,13 @@ func (m *ProcessManager) AddListener(listener api.ProcessListener) {
func (m *ProcessManager) DeleteListener(listener api.ProcessListener) {
m.storage.DeleteListener(listener)
}
+
+func (m *ProcessManager) ShouldMonitor(pid int32) bool {
+ monitor := false
+ for _, finder := range m.finders {
+ if finder.ShouldMonitor(pid) {
+ monitor = true
+ }
+ }
+ return monitor
+}
diff --git a/pkg/process/finders/scanner/finder.go b/pkg/process/finders/scanner/finder.go
index 81648d0..e932fbf 100644
--- a/pkg/process/finders/scanner/finder.go
+++ b/pkg/process/finders/scanner/finder.go
@@ -83,13 +83,29 @@ func (p *ProcessFinder) DetectType() api.ProcessDetectType {
return api.Scanner
}
-func (p *ProcessFinder) ValidateProcessIsSame(p1, p2 base.DetectedProcess) bool {
+func (p *ProcessFinder) ShouldMonitor(pid int32) bool {
+ curProcess, err := process.NewProcess(pid)
+ if err != nil {
+ return false
+ }
+ var buildProcess *Process
+ if p.conf.ScanMode == Regex {
+ buildProcess = p.regexBuildProcess(curProcess)
+ }
+ if buildProcess != nil {
+ p.manager.AddDetectedProcess([]api.DetectedProcess{buildProcess})
+ return true
+ }
+ return false
+}
+
+func (p *ProcessFinder) ValidateProcessIsSame(p1, p2 api.DetectedProcess) bool {
vm1 := p1.(*Process)
vm2 := p2.(*Process)
return p1.Pid() == p2.Pid() && vm1.cmd == vm2.cmd && p1.Entity().SameWith(p2.Entity())
}
-func (p *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps base.DetectedProcess) *v3.EBPFProcessProperties {
+func (p *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps api.DetectedProcess) *v3.EBPFProcessProperties {
hostProcess := &v3.EBPFHostProcessMetadata{}
hostProcess.Pid = ps.Pid()
hostProcess.Entity = &v3.EBPFProcessEntityMetadata{
@@ -120,7 +136,7 @@ func (p *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps b
return properties
}
-func (p *ProcessFinder) BuildNecessaryProperties(ps base.DetectedProcess) []*commonv3.KeyStringValuePair {
+func (p *ProcessFinder) BuildNecessaryProperties(ps api.DetectedProcess) []*commonv3.KeyStringValuePair {
return []*commonv3.KeyStringValuePair{
{
Key: "support_ebpf_profiling",
@@ -129,7 +145,7 @@ func (p *ProcessFinder) BuildNecessaryProperties(ps base.DetectedProcess) []*com
}
}
-func (p *ProcessFinder) ParseProcessID(ps base.DetectedProcess, downstream *v3.EBPFProcessDownstream) string {
+func (p *ProcessFinder) ParseProcessID(ps api.DetectedProcess, downstream *v3.EBPFProcessDownstream) string {
if downstream.GetHostProcess() == nil {
return ""
}
@@ -156,7 +172,7 @@ func (p *ProcessFinder) startWatch() {
}
func (p *ProcessFinder) findAndReportProcesses() {
- var detectFunc func() ([]base.DetectedProcess, error)
+ var detectFunc func() ([]api.DetectedProcess, error)
if p.conf.ScanMode == Regex {
detectFunc = p.regexFindProcesses
} else if p.conf.ScanMode == Agent {
@@ -170,7 +186,7 @@ func (p *ProcessFinder) findAndReportProcesses() {
}
}
-func (p *ProcessFinder) regexFindProcesses() ([]base.DetectedProcess, error) {
+func (p *ProcessFinder) regexFindProcesses() ([]api.DetectedProcess, error) {
// find all process
processes, err := p.regexFindMatchedProcesses()
if err != nil {
@@ -178,7 +194,7 @@ func (p *ProcessFinder) regexFindProcesses() ([]base.DetectedProcess, error) {
}
// report to the manager
- psList := make([]base.DetectedProcess, 0)
+ psList := make([]api.DetectedProcess, 0)
for _, ps := range processes {
psList = append(psList, ps)
}
@@ -208,14 +224,14 @@ func (p *ProcessFinder) getProcessTempDir(pro *process.Process) (string, error)
return "", fmt.Errorf("could not found tmp directory for pid: %d", pro.Pid)
}
-func (p *ProcessFinder) agentFindProcesses() ([]base.DetectedProcess, error) {
+func (p *ProcessFinder) agentFindProcesses() ([]api.DetectedProcess, error) {
// all system processes
processes, err := process.ProcessesWithContext(p.ctx)
if err != nil {
return nil, err
}
// find all matches processes
- findedProcesses := make([]base.DetectedProcess, 0)
+ findedProcesses := make([]api.DetectedProcess, 0)
for _, pro := range processes {
// already contains the processes
pid := pro.Pid
@@ -323,6 +339,30 @@ func (p *ProcessFinder) buildProcessFromAgentMetadata(pro *process.Process, meta
return NewProcessByAgent(pro, cmdline, agent)
}
+func (p *ProcessFinder) regexBuildProcess(pro *process.Process) *Process {
+ finderConfig, cmdline, err := p.findMatchesFinder(pro)
+ if err != nil {
+ log.Warnf("failed to match process %d, reason: %v", pro.Pid, err)
+ return nil
+ }
+ if finderConfig == nil {
+ return nil
+ }
+
+ // build the linux process and add to the list
+ ps := NewProcessByRegex(pro, cmdline, finderConfig)
+ ps.entity.Layer = finderConfig.Layer
+ ps.entity.ServiceName, err = p.buildEntity(err, ps, finderConfig.serviceNameBuilder)
+ ps.entity.InstanceName, err = p.buildEntity(err, ps, finderConfig.instanceNameBuilder)
+ ps.entity.ProcessName, err = p.buildEntity(err, ps, finderConfig.processNameBuilder)
+ ps.entity.Labels = finderConfig.ParsedLabels
+ if err != nil {
+ log.Warnf("failed to build the process data for pid: %d, reason: %v", pro.Pid, err)
+ return nil
+ }
+ return ps
+}
+
func (p *ProcessFinder) regexFindMatchedProcesses() ([]*Process, error) {
// all system processes
processes, err := process.ProcessesWithContext(p.ctx)
@@ -332,28 +372,8 @@ func (p *ProcessFinder) regexFindMatchedProcesses() ([]*Process, error) {
// find all matches processes
findedProcesses := make([]*Process, 0)
for _, pro := range processes {
- // find the matched process finder
- finderConfig, cmdline, err := p.findMatchesFinder(pro)
- if err != nil {
- log.Warnf("failed to match process %d, reason: %v", pro.Pid, err)
- continue
- }
- if finderConfig == nil {
- continue
- }
-
- // build the linux process and add to the list
- ps := NewProcessByRegex(pro, cmdline, finderConfig)
- ps.entity.Layer = finderConfig.Layer
- ps.entity.ServiceName, err = p.buildEntity(err, ps, finderConfig.serviceNameBuilder)
- ps.entity.InstanceName, err = p.buildEntity(err, ps, finderConfig.instanceNameBuilder)
- ps.entity.ProcessName, err = p.buildEntity(err, ps, finderConfig.processNameBuilder)
- ps.entity.Labels = finderConfig.ParsedLabels
- if err != nil {
- log.Warnf("failed to build the process data for pid: %d, reason: %v", pro.Pid, err)
- continue
- } else {
- findedProcesses = append(findedProcesses, ps)
+ if curProcess := p.regexBuildProcess(pro); curProcess != nil {
+ findedProcesses = append(findedProcesses, curProcess)
}
}
if len(findedProcesses) == 0 {
diff --git a/pkg/process/finders/scanner/process.go b/pkg/process/finders/scanner/process.go
index ae5ebed..87eeb3c 100644
--- a/pkg/process/finders/scanner/process.go
+++ b/pkg/process/finders/scanner/process.go
@@ -28,6 +28,8 @@ import (
"github.com/apache/skywalking-rover/pkg/tools/profiling"
)
+var listenStatus = "LISTEN"
+
type Process struct {
// original reference
original *process.Process
@@ -116,13 +118,27 @@ func (p *Process) ExposePorts() []int {
}
ports := make([]int, 0)
for _, con := range connections {
- if con.Status == "LISTEN" {
+ if con.Status == listenStatus {
ports = append(ports, int(con.Laddr.Port))
}
}
return ports
}
+func (p *Process) ExposeHosts() []string {
+ connections, err := p.original.Connections()
+ if err != nil {
+ log.Warnf("error getting the process connections, pid: %d, error: %v", p.pid, err)
+ }
+ hosts := make([]string, 0)
+ for _, con := range connections {
+ if con.Status == listenStatus {
+ hosts = append(hosts, con.Laddr.IP)
+ }
+ }
+ return hosts
+}
+
func requiredNotNull(err error, key, value string) error {
if err != nil {
return err
diff --git a/pkg/process/finders/storage.go b/pkg/process/finders/storage.go
index f382f2f..16314ee 100644
--- a/pkg/process/finders/storage.go
+++ b/pkg/process/finders/storage.go
@@ -237,7 +237,7 @@ func (s *ProcessStorage) processesReport(waitReportProcesses []*ProcessContext)
return nil
}
-func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, processes []base.DetectedProcess) {
+func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, processes []api.DetectedProcess) {
s.mutex.Lock()
defer s.mutex.Unlock()
@@ -249,7 +249,11 @@ func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, pr
existingProcessHasFounded[p] = false
}
+ addProcessBuilder := s.newProcessEventBuilder(ProcessOperateAdd)
for _, syncProcess := range processes {
+ if syncProcess == nil {
+ continue
+ }
founded := false
for _, existingProcess := range existingProcesses {
if syncProcess.Pid() == existingProcess.Pid() && syncProcess.Entity().SameWith(existingProcess.Entity()) {
@@ -262,10 +266,13 @@ func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, pr
// if not found in existing processes, need to add this process
if !founded {
- newProcesses = append(newProcesses, s.constructNewProcessContext(finder, syncProcess))
+ processContext := s.constructNewProcessContext(finder, syncProcess)
+ newProcesses = append(newProcesses, processContext)
+ addProcessBuilder.AddProcess(syncProcess.Pid(), newProcesses[len(newProcesses)-1])
log.Infof("detected new process: pid: %d, entity: %s", syncProcess.Pid(), syncProcess.Entity())
}
}
+ addProcessBuilder.Send()
// log the dead processes
eventBuilder := s.newProcessEventBuilder(ProcessOperateDelete)
@@ -281,7 +288,7 @@ func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, pr
eventBuilder.Send()
}
-func (s *ProcessStorage) constructNewProcessContext(finder api.ProcessDetectType, process base.DetectedProcess) *ProcessContext {
+func (s *ProcessStorage) constructNewProcessContext(finder api.ProcessDetectType, process api.DetectedProcess) *ProcessContext {
exporsedPorts := make(map[int]bool)
for _, p := range process.ExposePorts() {
exporsedPorts[p] = true
diff --git a/pkg/process/module.go b/pkg/process/module.go
index 769880e..3a8903f 100644
--- a/pkg/process/module.go
+++ b/pkg/process/module.go
@@ -98,3 +98,11 @@ func (m *Module) AddListener(listener api.ProcessListener) {
func (m *Module) DeleteListener(listener api.ProcessListener) {
m.manager.DeleteListener(listener)
}
+
+func (m *Module) ShouldMonitor(pid int32) bool {
+ return m.manager.ShouldMonitor(pid)
+}
+
+func (m *Module) NodeName() string {
+ return m.config.Kubernetes.NodeName
+}
diff --git a/pkg/profiling/continuous/checker/bpf/network/reader.go b/pkg/profiling/continuous/checker/bpf/network/reader.go
index cacaa98..721e17f 100644
--- a/pkg/profiling/continuous/checker/bpf/network/reader.go
+++ b/pkg/profiling/continuous/checker/bpf/network/reader.go
@@ -18,12 +18,12 @@
package network
import (
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
type BufferDirection uint8
-var protocolAnalyzers map[events.ConnectionProtocol]ProtocolAnalyzer
+var protocolAnalyzers map[enums.ConnectionProtocol]ProtocolAnalyzer
var (
BufferDirectionRequest BufferDirection = 1
@@ -31,14 +31,14 @@ var (
)
func init() {
- protocolAnalyzers = make(map[events.ConnectionProtocol]ProtocolAnalyzer)
- protocolAnalyzers[events.ConnectionProtocolHTTP] = NewHTTP1Analyzer()
+ protocolAnalyzers = make(map[enums.ConnectionProtocol]ProtocolAnalyzer)
+ protocolAnalyzers[enums.ConnectionProtocolHTTP] = NewHTTP1Analyzer()
}
type networkBufferInBPF struct {
Timestamp uint64
ChannelRef uint64
- Protocol events.ConnectionProtocol
+ Protocol enums.ConnectionProtocol
Direction BufferDirection
Size uint16
Pid uint32
diff --git a/pkg/profiling/task/network/analyze/base/connection.go b/pkg/profiling/task/network/analyze/base/connection.go
index cad759b..2bd1cc9 100644
--- a/pkg/profiling/task/network/analyze/base/connection.go
+++ b/pkg/profiling/task/network/analyze/base/connection.go
@@ -19,7 +19,7 @@ package base
import (
"github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
type ConnectionContext struct {
@@ -30,11 +30,11 @@ type ConnectionContext struct {
SocketFD uint32
LocalProcesses []api.ProcessInterface
ConnectionClosed bool
- Protocol events.ConnectionProtocol
+ Protocol enums.ConnectionProtocol
IsSSL bool
// socket metadata
- Role events.ConnectionRole
+ Role enums.ConnectionRole
LocalIP string
LocalPort uint16
RemoteIP string
@@ -67,7 +67,7 @@ type ActiveConnectionInBPF struct {
RandomID uint64
Pid uint32
SocketFD uint32
- Role events.ConnectionRole
+ Role enums.ConnectionRole
SocketFamily uint32
RemoteAddrV4 uint32
@@ -91,7 +91,7 @@ type ActiveConnectionInBPF struct {
_ uint64
// protocol of connection
- Protocol events.ConnectionProtocol
+ Protocol enums.ConnectionProtocol
// the connect event is already sent
ConnectEventIsSent uint8
IsSSL uint8
diff --git a/pkg/profiling/task/network/analyze/base/context.go b/pkg/profiling/task/network/analyze/base/context.go
index 3f09987..de60778 100644
--- a/pkg/profiling/task/network/analyze/base/context.go
+++ b/pkg/profiling/task/network/analyze/base/context.go
@@ -22,15 +22,15 @@ import (
"encoding/json"
"errors"
"fmt"
- "net"
"sync"
- "unsafe"
"github.com/apache/skywalking-rover/pkg/module"
"github.com/apache/skywalking-rover/pkg/process/api"
"github.com/apache/skywalking-rover/pkg/profiling/task/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/bpf"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/ip"
"github.com/cilium/ebpf"
@@ -129,7 +129,7 @@ func (c *AnalyzerContext) handleSocketParseQueue(ctx context.Context) {
for {
select {
case cc := <-c.sockParseQueue:
- socket, err := ParseSocket(cc.LocalPid, cc.SocketFD)
+ socket, err := ip.ParseSocket(cc.LocalPid, cc.SocketFD)
if err != nil {
// if the remote port of connection is empty, then this connection not available basically
if cc.RemotePort == 0 {
@@ -168,20 +168,20 @@ func (c *AnalyzerContext) handleSocketConnectEvent(data interface{}) {
con.RemotePort = uint16(event.RemoteAddrPort)
con.LocalPort = uint16(event.LocalAddrPort)
if event.SocketFamily == unix.AF_INET {
- con.LocalIP = parseAddressV4(event.LocalAddrV4)
- con.RemoteIP = parseAddressV4(event.RemoteAddrV4)
+ con.LocalIP = ip.ParseIPV4(event.LocalAddrV4)
+ con.RemoteIP = ip.ParseIPV4(event.RemoteAddrV4)
} else {
- con.LocalIP = parseAddressV6(event.LocalAddrV6)
- con.RemoteIP = parseAddressV6(event.RemoteAddrV6)
+ con.LocalIP = ip.ParseIPV6(event.LocalAddrV6)
+ con.RemoteIP = ip.ParseIPV6(event.RemoteAddrV6)
}
} else {
// if the remote address exists then setting it
if event.RemoteAddrPort != 0 {
con.RemotePort = uint16(event.RemoteAddrPort)
if event.SocketFamily == unix.AF_INET {
- con.RemoteIP = parseAddressV4(event.RemoteAddrV4)
+ con.RemoteIP = ip.ParseIPV4(event.RemoteAddrV4)
} else {
- con.RemoteIP = parseAddressV6(event.RemoteAddrV6)
+ con.RemoteIP = ip.ParseIPV6(event.RemoteAddrV6)
}
}
c.sockParseQueue <- con
@@ -192,7 +192,7 @@ func (c *AnalyzerContext) handleSocketConnectEvent(data interface{}) {
l.ReceiveNewConnection(con, event)
}
- // add to the context
+ // add to the common
c.saveActiveConnection(con)
}
@@ -303,10 +303,10 @@ func (c *AnalyzerContext) lookupTheActiveConnectionInBPf(connection *ConnectionC
log.Debugf("found the active connection, conid: %d, data: %s", connection.ConnectionID, string(marshal))
}
- if connection.Role == events.ConnectionRoleUnknown && activeConnection.Role != events.ConnectionRoleUnknown {
+ if connection.Role == enums.ConnectionRoleUnknown && activeConnection.Role != enums.ConnectionRoleUnknown {
connection.Role = activeConnection.Role
}
- if connection.Protocol == events.ConnectionProtocolUnknown && activeConnection.Protocol != events.ConnectionProtocolUnknown {
+ if connection.Protocol == enums.ConnectionProtocolUnknown && activeConnection.Protocol != enums.ConnectionProtocolUnknown {
connection.Protocol = activeConnection.Protocol
}
if !connection.IsSSL && activeConnection.IsSSL == 1 {
@@ -334,11 +334,11 @@ func (c *AnalyzerContext) processCachedCloseEvents() {
}
cc := c.NewConnectionContext(event.ConID, event.RandomID, event.Pid, event.SocketFD, processes, true)
if event.SocketFamily == unix.AF_INET {
- cc.RemoteIP = parseAddressV4(event.RemoteAddrV4)
- cc.LocalIP = parseAddressV4(event.LocalAddrV4)
+ cc.RemoteIP = ip.ParseIPV4(event.RemoteAddrV4)
+ cc.LocalIP = ip.ParseIPV4(event.LocalAddrV4)
} else if event.SocketFamily == unix.AF_INET6 {
- cc.RemoteIP = parseAddressV6(event.RemoteAddrV6)
- cc.LocalIP = parseAddressV6(event.LocalAddrV6)
+ cc.RemoteIP = ip.ParseIPV6(event.RemoteAddrV6)
+ cc.LocalIP = ip.ParseIPV6(event.LocalAddrV6)
} else {
continue
}
@@ -376,10 +376,10 @@ func (c *AnalyzerContext) foundAndDeleteConnection(event *events.SocketCloseEven
func (c *AnalyzerContext) combineClosedConnection(active *ConnectionContext, closed *events.SocketCloseEvent) *ConnectionContext {
active.ConnectionClosed = true
- if active.Role == events.ConnectionRoleUnknown && closed.Role != events.ConnectionRoleUnknown {
+ if active.Role == enums.ConnectionRoleUnknown && closed.Role != enums.ConnectionRoleUnknown {
active.Role = closed.Role
}
- if active.Protocol == events.ConnectionProtocolUnknown && closed.Protocol != events.ConnectionProtocolUnknown {
+ if active.Protocol == enums.ConnectionProtocolUnknown && closed.Protocol != enums.ConnectionProtocolUnknown {
active.Protocol = closed.Protocol
}
if !active.IsSSL && closed.IsSSL == 1 {
@@ -412,11 +412,3 @@ func (c *AnalyzerContext) appendClosedConnection(con *ConnectionContext) {
c.closedConnections = append(c.closedConnections, con)
}
-
-func parseAddressV4(val uint32) string {
- return net.IP((*(*[net.IPv4len]byte)(unsafe.Pointer(&val)))[:]).String()
-}
-
-func parseAddressV6(val [16]uint8) string {
- return net.IP((*(*[net.IPv6len]byte)(unsafe.Pointer(&val)))[:]).String()
-}
diff --git a/pkg/profiling/task/network/analyze/base/metrics.go b/pkg/profiling/task/network/analyze/base/metrics.go
index 3514d02..60ec728 100644
--- a/pkg/profiling/task/network/analyze/base/metrics.go
+++ b/pkg/profiling/task/network/analyze/base/metrics.go
@@ -22,8 +22,8 @@ import (
"time"
"github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
"github.com/apache/skywalking-rover/pkg/tools"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
@@ -96,11 +96,11 @@ func (m *MetricsBuilder) MetricPrefix() string {
return m.prefix
}
-func (m *MetricsBuilder) BuildBasicMeterLabels(traffic *ProcessTraffic, local api.ProcessInterface) (events.ConnectionRole, []*agentv3.Label) {
+func (m *MetricsBuilder) BuildBasicMeterLabels(traffic *ProcessTraffic, local api.ProcessInterface) (enums.ConnectionRole, []*agentv3.Label) {
curRole := traffic.Role
// add the default role
- if curRole == events.ConnectionRoleUnknown {
- curRole = events.ConnectionRoleClient
+ if curRole == enums.ConnectionRoleUnknown {
+ curRole = enums.ConnectionRoleClient
}
labels := make([]*agentv3.Label, 0)
diff --git a/pkg/profiling/task/network/analyze/base/tcpresolver.go b/pkg/profiling/task/network/analyze/base/tcpresolver.go
deleted file mode 100644
index 2af0e6e..0000000
--- a/pkg/profiling/task/network/analyze/base/tcpresolver.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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 base
-
-import (
- "encoding/binary"
- "fmt"
- "net"
- "os"
- "regexp"
- "strconv"
- "strings"
-
- "github.com/hashicorp/go-multierror"
-
- "github.com/apache/skywalking-rover/pkg/tools/host"
-)
-
-var (
- notBlankRegex = regexp.MustCompile(`\s+`)
- ipv4StrLen = 8
- ipv6StrLen = 32
-)
-
-type SocketPair struct {
- SrcIP string
- SrcPort uint16
- DestIP string
- DestPort uint16
-}
-
-func ParseSocket(pid, sockfd uint32) (*SocketPair, error) {
- link := fmt.Sprintf("/proc/%d/fd/%d", pid, sockfd)
- dest, err := os.Readlink(host.GetFileInHost(link))
- if err != nil {
- return nil, fmt.Errorf("could not read the socket real link: %v", err)
- }
- if !strings.HasPrefix(dest, "socket:[") {
- return nil, fmt.Errorf("current file is not socket: %s", dest)
- }
-
- inode := strings.TrimSuffix(strings.TrimPrefix(dest, "socket:["), "]")
- var s *SocketPair
- s, err = foundAddressByFile(s, err, fmt.Sprintf(host.GetFileInHost("/proc/%d/net/tcp"), pid), inode)
- s, err = foundAddressByFile(s, err, fmt.Sprintf(host.GetFileInHost("/proc/%d/net/tcp6"), pid), inode)
- return s, err
-}
-
-func foundAddressByFile(s *SocketPair, exitedError error, filename, inode string) (*SocketPair, error) {
- if s != nil {
- return s, nil
- }
- data, err := os.ReadFile(filename)
- if err != nil {
- return nil, multierror.Append(exitedError, err)
- }
-
- lines := strings.Split(string(data), "\n")
- for _, line := range lines[1 : len(lines)-1] {
- source := notBlankRegex.Split(strings.TrimSpace(line), -1)
- if len(source) < 10 {
- continue
- }
- tcpINode := source[9]
- if tcpINode != inode {
- continue
- }
-
- // ignore local listenning records
- destIP, destPort, err := parseAddr(source[2])
- if err != nil {
- return nil, multierror.Append(exitedError, fmt.Errorf("parsing address in file failure: %s, error: %s", filename, err))
- }
-
- // source ip and port
- ip, port, err := parseAddr(source[1])
- if err != nil {
- return nil, multierror.Append(exitedError, fmt.Errorf("parsing address in file failure: %s, error: %s", filename, err))
- }
-
- return &SocketPair{
- SrcIP: ip,
- SrcPort: port,
- DestIP: destIP,
- DestPort: destPort,
- }, nil
- }
- return nil, multierror.Append(exitedError, fmt.Errorf("could not found the socket: %s, in file: %s", inode, filename))
-}
-
-func parseAddr(str string) (ipAddr string, port uint16, err error) {
- fields := strings.Split(str, ":")
- if len(fields) < 2 {
- return "", 0, fmt.Errorf("netstat: not enough fields: %v", fields)
- }
- var ip net.IP
- switch len(fields[0]) {
- case ipv4StrLen:
- ip, err = parseIPv4(fields[0])
- case ipv6StrLen:
- ip, err = parseIPv6(fields[0])
- default:
- err = fmt.Errorf("netstat: bad formatted string: %v", fields[0])
- }
- if err != nil {
- return "", 0, err
- }
- v, err := strconv.ParseUint(fields[1], 16, 16)
- if err != nil {
- return "", 0, err
- }
- return ip.String(), uint16(v), nil
-}
-
-func parseIPv4(s string) (net.IP, error) {
- v, err := strconv.ParseUint(s, 16, 32)
- if err != nil {
- return nil, err
- }
- ip := make(net.IP, net.IPv4len)
- binary.LittleEndian.PutUint32(ip, uint32(v))
- return ip, nil
-}
-
-func parseIPv6(s string) (net.IP, error) {
- ip := make(net.IP, net.IPv6len)
- const grpLen = 4
- i, j := 0, 4
- for s != "" {
- grp := s[0:8]
- u, err := strconv.ParseUint(grp, 16, 32)
- binary.LittleEndian.PutUint32(ip[i:j], uint32(u))
- if err != nil {
- return nil, err
- }
- i, j = i+grpLen, j+grpLen
- s = s[8:]
- }
- return ip, nil
-}
diff --git a/pkg/profiling/task/network/analyze/base/traffic.go b/pkg/profiling/task/network/analyze/base/traffic.go
index 8e96e39..45495ed 100644
--- a/pkg/profiling/task/network/analyze/base/traffic.go
+++ b/pkg/profiling/task/network/analyze/base/traffic.go
@@ -22,8 +22,8 @@ import (
"github.com/apache/skywalking-rover/pkg/logger"
"github.com/apache/skywalking-rover/pkg/process/api"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
"github.com/apache/skywalking-rover/pkg/tools"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
var log = logger.GetLogger("profiling", "task", "network", "analyze")
@@ -50,8 +50,8 @@ type ProcessTraffic struct {
RemoteProcesses []api.ProcessInterface
// connection basic information
- Role events.ConnectionRole
- Protocol events.ConnectionProtocol
+ Role enums.ConnectionRole
+ Protocol enums.ConnectionProtocol
IsSSL bool
// metrics
@@ -136,12 +136,12 @@ func (t *TrafficAnalyzer) CombineConnectionToTraffics(connections []*ConnectionC
pidToRemoteKey.LocalPid = con.LocalPid
pidToRemoteKey.RemoteIP = con.RemoteIP
// if connection role is not server side, then add the remote port
- if con.Role != events.ConnectionRoleServer {
+ if con.Role != enums.ConnectionRoleServer {
// uniformly identified as a client
- pidToRemoteKey.Role = events.ConnectionRoleClient
+ pidToRemoteKey.Role = enums.ConnectionRoleClient
pidToRemoteKey.RemotePort = con.RemotePort
} else {
- pidToRemoteKey.Role = events.ConnectionRoleServer
+ pidToRemoteKey.Role = enums.ConnectionRoleServer
}
traffic := pidToRemoteTraffic[pidToRemoteKey]
traffic = t.generateOrCombineTraffic(traffic, con, 0)
@@ -187,20 +187,20 @@ func (t *ProcessTraffic) RemoteProcessIsProfiling() bool {
}
func (t *TrafficAnalyzer) tryingToGenerateTheRoleWhenRemotePidCannotFound(con *ConnectionContext) {
- if con.Role != events.ConnectionRoleUnknown {
+ if con.Role != enums.ConnectionRoleUnknown {
return
}
// local process address or process could not found, then could analyze the role
if con.LocalPort == 0 || len(con.LocalProcesses) == 0 {
return
}
- var role events.ConnectionRole
+ var role enums.ConnectionRole
// if port is expose, and remote address is not local pid
// then the role of connection is server side usually
if con.LocalProcesses[0].PortIsExpose(int(con.LocalPort)) {
- role = events.ConnectionRoleServer
+ role = enums.ConnectionRoleServer
} else {
- role = events.ConnectionRoleClient
+ role = enums.ConnectionRoleClient
}
con.Role = role
@@ -224,10 +224,10 @@ func (t *TrafficAnalyzer) generateOrCombineTraffic(traffic *ProcessTraffic, con
if len(traffic.LocalProcesses) == 0 && len(con.LocalProcesses) > 0 {
traffic.LocalProcesses = con.LocalProcesses
}
- if traffic.Role == events.ConnectionRoleUnknown && con.Role != events.ConnectionRoleUnknown {
+ if traffic.Role == enums.ConnectionRoleUnknown && con.Role != enums.ConnectionRoleUnknown {
traffic.Role = con.Role
}
- if traffic.Protocol == events.ConnectionProtocolUnknown && con.Protocol != events.ConnectionProtocolUnknown {
+ if traffic.Protocol == enums.ConnectionProtocolUnknown && con.Protocol != enums.ConnectionProtocolUnknown {
traffic.Protocol = con.Protocol
}
if !traffic.IsSSL && con.IsSSL {
@@ -284,7 +284,7 @@ func (t *TrafficAnalyzer) buildCache(connections []*ConnectionContext) {
}
} else if t.ipNotEmpty(con.RemoteIP, con.RemotePort) {
// if server side is envoy
- if con.Role == events.ConnectionRoleServer && len(con.LocalProcesses) > 0 {
+ if con.Role == enums.ConnectionRoleServer && len(con.LocalProcesses) > 0 {
name, err := con.LocalProcesses[0].ExeName()
if err != nil {
log.Warnf("get process exe name failure, pid: %d, error: %v", con.LocalPid, err)
@@ -312,7 +312,7 @@ func (t *TrafficAnalyzer) buildCache(connections []*ConnectionContext) {
func (t *TrafficAnalyzer) processExportPortAnalyze(con *ConnectionContext) {
// if the process exists, role of connection is server mode and local port is exists1
// add the detected port into the processes
- if len(con.LocalProcesses) > 0 && con.Role == events.ConnectionRoleServer && con.LocalPort > 0 {
+ if len(con.LocalProcesses) > 0 && con.Role == enums.ConnectionRoleServer && con.LocalPort > 0 {
for _, p := range con.LocalProcesses {
p.DetectNewExposePort(int(con.LocalPort))
}
@@ -350,7 +350,7 @@ func (t *TrafficAnalyzer) findRemotePidWhenContainsFullAddress(con *ConnectionCo
log.Debugf("found in peer cache: %s:%d->%s:%d, pid: %d", con.RemoteIP, con.RemotePort, con.LocalIP, con.LocalPort, data.Pid)
// if current connection is unknown, but peer network has role, then just use the revert role
// such as: cur:(a->b) unknown, remote:(b->a) client, then current connection must have the server role
- if con.Role == events.ConnectionRoleUnknown && data.Role != events.ConnectionRoleUnknown {
+ if con.Role == enums.ConnectionRoleUnknown && data.Role != enums.ConnectionRoleUnknown {
con.Role = data.Role.Revert()
}
return data.Pid
@@ -358,7 +358,7 @@ func (t *TrafficAnalyzer) findRemotePidWhenContainsFullAddress(con *ConnectionCo
log.Debugf("not found in peer cache: %s:%d->%s:%d", con.RemoteIP, con.RemotePort, con.LocalIP, con.LocalPort)
// if current role is client side, and localIP:port match to envoy
- if con.Role == events.ConnectionRoleClient {
+ if con.Role == enums.ConnectionRoleClient {
// need update the remote address to real address
addr := t.envoyAcceptClientAddressCache[PeerAddress{
RemoteIP: con.LocalIP,
@@ -473,19 +473,19 @@ type AddressWithPid struct {
type PidMatchTrafficKey struct {
LocalPid uint32
RemotePid uint32
- Role events.ConnectionRole
+ Role enums.ConnectionRole
}
type PidToRemoteTrafficKey struct {
LocalPid uint32
- Role events.ConnectionRole
+ Role enums.ConnectionRole
RemoteIP string
RemotePort uint16
}
type PidWithRole struct {
Pid uint32
- Role events.ConnectionRole
+ Role enums.ConnectionRole
}
func (t *TrafficAnalyzer) ipNotEmpty(ip string, port uint16) bool {
diff --git a/pkg/profiling/task/network/analyze/events/data.go b/pkg/profiling/task/network/analyze/events/data.go
index 46b0ae2..9ca242d 100644
--- a/pkg/profiling/task/network/analyze/events/data.go
+++ b/pkg/profiling/task/network/analyze/events/data.go
@@ -19,42 +19,14 @@ package events
import (
"fmt"
-)
-type SocketDataBuffer interface {
- // GenerateConnectionID for identity the buffer belong which connection
- GenerateConnectionID() string
- // BufferData of the buffer
- BufferData() []byte
- // TotalSize of socket data, the data may exceed the size of the BufferData()
- TotalSize() uint64
- // Direction of the data, send or receive
- Direction() SocketDataDirection
- // BufferStartPosition the buffer start index
- BufferStartPosition() int
- // BufferLen the buffer data length
- BufferLen() int
- // DataID data id of the buffer
- DataID() uint64
- // DataSequence the data sequence under same data id
- DataSequence() int
- // IsStart this buffer is start of the same data id
- IsStart() bool
- // IsFinished this buffer is finish of the same data id
- IsFinished() bool
- // HaveReduceDataAfterChunk check have reduced data after current buffer
- HaveReduceDataAfterChunk() bool
-
- // StartTime the data start timestamp
- StartTime() uint64
- // EndTime the data end timestamp
- EndTime() uint64
-}
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
+)
type SocketDataUploadEvent struct {
- Protocol ConnectionProtocol
+ Protocol enums.ConnectionProtocol
HaveReduce uint8
- Direction0 SocketDataDirection
+ Direction0 enums.SocketDataDirection
Finished uint8
Sequence0 uint16
DataLen uint16
@@ -87,7 +59,7 @@ func (s *SocketDataUploadEvent) EndTime() uint64 {
return s.EndTime0
}
-func (s *SocketDataUploadEvent) Direction() SocketDataDirection {
+func (s *SocketDataUploadEvent) Direction() enums.SocketDataDirection {
return s.Direction0
}
@@ -119,37 +91,23 @@ func (s *SocketDataUploadEvent) HaveReduceDataAfterChunk() bool {
return s.HaveReduce == 1
}
-type SocketDataEventLimited struct {
- SocketDataBuffer
- From int
- Size int
-}
-
-func (s *SocketDataEventLimited) BufferData() []byte {
- return s.SocketDataBuffer.BufferData()[s.From:s.Size]
-}
-
-func (s *SocketDataEventLimited) BufferLen() int {
- return s.Size - s.From
-}
-
-func (s *SocketDataEventLimited) BufferStartPosition() int {
- return s.From
-}
-
type SocketDetailEvent struct {
ConnectionID uint64
RandomID uint64
- DataID uint64
+ DataID0 uint64
TotalPackageSize uint64
IfIndex uint32
PackageCount uint8
- FuncName SocketFunctionName
+ FuncName enums.SocketFunctionName
RTTCount uint8
- Protocol ConnectionProtocol
+ Protocol enums.ConnectionProtocol
RTTTime uint32
}
+func (s *SocketDetailEvent) DataID() uint64 {
+ return s.DataID0
+}
+
func (s *SocketDetailEvent) GenerateConnectionID() string {
return fmt.Sprintf("%d_%d", s.ConnectionID, s.RandomID)
}
diff --git a/pkg/profiling/task/network/analyze/events/sockets.go b/pkg/profiling/task/network/analyze/events/sockets.go
index dca74f3..60e9842 100644
--- a/pkg/profiling/task/network/analyze/events/sockets.go
+++ b/pkg/profiling/task/network/analyze/events/sockets.go
@@ -17,6 +17,8 @@
package events
+import "github.com/apache/skywalking-rover/pkg/tools/enums"
+
// SocketConnectEvent Socket have been connection/accept event
type SocketConnectEvent struct {
ConID uint64
@@ -28,7 +30,7 @@ type SocketConnectEvent struct {
FuncName uint32
// socket information if exists
- Role ConnectionRole
+ Role enums.ConnectionRole
SocketFamily uint32
RemoteAddrV4 uint32
RemoteAddrV6 [16]uint8
@@ -44,10 +46,10 @@ type SocketCloseEvent struct {
ExeTime uint64
Pid uint32
SocketFD uint32
- Protocol ConnectionProtocol
+ Protocol enums.ConnectionProtocol
IsSSL uint8
Fix uint16
- Role ConnectionRole
+ Role enums.ConnectionRole
SocketFamily uint32
RemoteAddrV4 uint32
diff --git a/pkg/profiling/task/network/analyze/layer4/events.go b/pkg/profiling/task/network/analyze/layer4/events.go
index ecbc0fa..6cece95 100644
--- a/pkg/profiling/task/network/analyze/layer4/events.go
+++ b/pkg/profiling/task/network/analyze/layer4/events.go
@@ -21,7 +21,7 @@ import (
"encoding/json"
"github.com/apache/skywalking-rover/pkg/logger"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"github.com/sirupsen/logrus"
)
@@ -38,7 +38,7 @@ type SocketExceptionOperationEvent struct {
LocalAddrV4 uint32
LocalAddrV6 [16]uint8
LocalAddrPort uint32
- Type events.SocketExceptionOperationType
+ Type enums.SocketExceptionOperationType
}
func (l *Listener) handleSocketExceptionOperationEvent(data interface{}) {
@@ -60,9 +60,9 @@ func (l *Listener) handleSocketExceptionOperationEvent(data interface{}) {
}
switch event.Type {
- case events.SocketExceptionOperationRetransmit:
+ case enums.SocketExceptionOperationRetransmit:
exceptionValue.RetransmitCount++
- case events.SocketExceptionOperationDrop:
+ case enums.SocketExceptionOperationDrop:
exceptionValue.DropCount++
default:
log.Warnf("unknown socket exception operation type: %d", event.Type)
diff --git a/pkg/profiling/task/network/analyze/layer4/listener.go b/pkg/profiling/task/network/analyze/layer4/listener.go
index 31ba86d..0c16145 100644
--- a/pkg/profiling/task/network/analyze/layer4/listener.go
+++ b/pkg/profiling/task/network/analyze/layer4/listener.go
@@ -32,6 +32,7 @@ import (
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/bpf"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
v3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
@@ -129,13 +130,13 @@ func (l *Listener) PreFlushConnectionMetrics(ccs []*base.ConnectionWithBPF, bpfL
// add the histogram data
var histogram *SocketDataHistogramWithHistory
- if key.DataDirection == events.SocketDataDirectionEgress {
- if key.DataType == events.SocketDataStaticsTypeExeTime {
+ if key.DataDirection == enums.SocketDataDirectionEgress {
+ if key.DataType == enums.SocketDataStaticsTypeExeTime {
histogram = layer4.WriteExeTimeHistogram
- } else if key.DataType == events.SocketDataStaticsTypeRTT {
+ } else if key.DataType == enums.SocketDataStaticsTypeRTT {
histogram = layer4.WriteRTTHistogram
}
- } else if key.DataDirection == events.SocketDataDirectionIngress {
+ } else if key.DataDirection == enums.SocketDataDirectionIngress {
histogram = layer4.ReadExeTimeHistogram
}
if histogram == nil {
@@ -152,7 +153,7 @@ func (l *Listener) PreFlushConnectionMetrics(ccs []*base.ConnectionWithBPF, bpfL
}
}
- // all the exception operations to the context
+ // all the exception operations to the common
exceptionContexts := l.cleanAndGetAllExceptionContexts()
l.combineExceptionToConnections(keyWithContext, exceptionContexts)
return nil
@@ -355,8 +356,8 @@ type HistogramDataKey struct {
ConnectionID uint64
RandomID uint64
Bucket uint64
- DataDirection events.SocketDataDirection
- DataType events.SocketDataStaticsType
+ DataDirection enums.SocketDataDirection
+ DataType enums.SocketDataStaticsType
Fix [6]byte
}
diff --git a/pkg/profiling/task/network/analyze/layer7/listener.go b/pkg/profiling/task/network/analyze/layer7/listener.go
index 5c4c0ba..55dd187 100644
--- a/pkg/profiling/task/network/analyze/layer7/listener.go
+++ b/pkg/profiling/task/network/analyze/layer7/listener.go
@@ -33,6 +33,7 @@ import (
protocol "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/bpf"
"github.com/apache/skywalking-rover/pkg/tools/btf"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"github.com/zekroTJA/timedmap"
)
@@ -135,7 +136,7 @@ func (l *Listener) QueryConnection(conID, randomID uint64) *base.ConnectionConte
return nil
}
-func (l *Listener) QueryProtocolMetrics(conMetrics *base.ConnectionMetricsContext, p events.ConnectionProtocol) protocol.Metrics {
+func (l *Listener) QueryProtocolMetrics(conMetrics *base.ConnectionMetricsContext, p enums.ConnectionProtocol) protocol.Metrics {
metrics := conMetrics.GetMetrics(ListenerName).(*protocols.ProtocolMetrics)
return metrics.GetProtocolMetrics(p)
}
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/base/analyzer.go b/pkg/profiling/task/network/analyze/layer7/protocols/base/analyzer.go
index 3154a34..ac12d93 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/base/analyzer.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/base/analyzer.go
@@ -27,9 +27,9 @@ import (
"github.com/apache/skywalking-rover/pkg/logger"
profiling "github.com/apache/skywalking-rover/pkg/profiling/task/base"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
const (
@@ -96,7 +96,7 @@ func (a *ProtocolAnalyzer) ReceiveSocketDetail(ctx Context, event *events.Socket
connectionID := event.GenerateConnectionID()
connection := a.getConnection(ctx, event.ConnectionID, event.RandomID)
- log.Debugf("receive detail from connection: %s, dataid: %d", connectionID, event.DataID)
+ log.Debugf("receive detail from connection: %s, dataid: %d", connectionID, event.DataID())
connection.buffer.AppendDetailEvent(event)
}
@@ -221,7 +221,7 @@ func (a *ProtocolAnalyzer) generateConnectionInfoKey(connectionID, randomID uint
type connectionInfo struct {
connectionID, randomID uint64
- connectionProtocol events.ConnectionProtocol
+ connectionProtocol enums.ConnectionProtocol
buffer *buffer.Buffer
metrics Metrics
metricsFromConnection bool
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/base/protocol.go b/pkg/profiling/task/network/analyze/layer7/protocols/base/protocol.go
index 2a236b9..3ca7dcb 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/base/protocol.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/base/protocol.go
@@ -22,13 +22,12 @@ import (
profiling "github.com/apache/skywalking-rover/pkg/profiling/task/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
type Protocol interface {
- Protocol() events.ConnectionProtocol
+ Protocol() enums.ConnectionProtocol
GenerateMetrics() Metrics
Init(config *profiling.TaskConfig)
@@ -39,7 +38,7 @@ type Protocol interface {
type Context interface {
QueryConnection(connectionID, randomID uint64) *base.ConnectionContext
- QueryProtocolMetrics(conMetrics *base.ConnectionMetricsContext, protocol events.ConnectionProtocol) Metrics
+ QueryProtocolMetrics(conMetrics *base.ConnectionMetricsContext, protocol enums.ConnectionProtocol) Metrics
}
type Metrics interface {
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/analyzer.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/analyzer.go
index e9bbd19..245e6dd 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/analyzer.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/analyzer.go
@@ -26,11 +26,10 @@ import (
"github.com/apache/skywalking-rover/pkg/logger"
profiling "github.com/apache/skywalking-rover/pkg/profiling/task/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
protocol "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"github.com/sirupsen/logrus"
)
@@ -72,8 +71,8 @@ func NewHTTP1Analyzer() protocol.Protocol {
}
}
-func (h *Analyzer) Protocol() events.ConnectionProtocol {
- return events.ConnectionProtocolHTTP
+func (h *Analyzer) Protocol() enums.ConnectionProtocol {
+ return enums.ConnectionProtocolHTTP
}
func (h *Analyzer) GenerateMetrics() protocol.Metrics {
@@ -151,11 +150,11 @@ func (h *Analyzer) handleResponse(connectionID uint64, metrics *ConnectionMetric
// append metrics
data := metrics.clientMetrics
- side := events.ConnectionRoleClient
- if request.Direction() == events.SocketDataDirectionIngress {
+ side := enums.ConnectionRoleClient
+ if request.Direction() == enums.SocketDataDirectionIngress {
// if receive the request, that's mean is server side
data = metrics.serverMetrics
- side = events.ConnectionRoleServer
+ side = enums.ConnectionRoleServer
}
data.Append(h.sampleConfig, request, response)
@@ -226,7 +225,7 @@ func (m *ConnectionMetrics) FlushMetrics(traffic *base.ProcessTraffic, metricsBu
// if the remote process is profiling, then used the client side
localMetrics := m.clientMetrics
remoteMetrics := m.serverMetrics
- if traffic.Role == events.ConnectionRoleServer {
+ if traffic.Role == enums.ConnectionRoleServer {
localMetrics = m.serverMetrics
remoteMetrics = m.clientMetrics
}
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/metrics.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/metrics.go
index f0db67f..28dd6d4 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/metrics.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/metrics.go
@@ -26,13 +26,14 @@ import (
"github.com/apache/skywalking-rover/pkg/process/api"
profiling "github.com/apache/skywalking-rover/pkg/profiling/task/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
- protocol "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/metrics"
"github.com/apache/skywalking-rover/pkg/tools"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"github.com/apache/skywalking-rover/pkg/tools/host"
+ protocol "github.com/apache/skywalking-rover/pkg/tools/tracing"
"github.com/docker/go-units"
@@ -174,7 +175,7 @@ func (u *URIMetrics) String() string {
}
type Trace struct {
- Trace protocol.TracingContext
+ Trace protocol.Context
RequestURI string
Request *reader.Request
Response *reader.Response
@@ -192,7 +193,7 @@ func (h *Trace) Flush(duration int64, process api.ProcessInterface, traffic *bas
logData.Tags = &logv3.LogTags{Data: make([]*commonv3.KeyStringValuePair, 0)}
logData.Tags.Data = append(logData.Tags.Data, &commonv3.KeyStringValuePair{Key: "LOG_KIND", Value: "NET_PROFILING_SAMPLED_TRACE"})
- // trace context
+ // trace common
traceContext := &logv3.TraceContext{}
traceContext.TraceId = h.Trace.TraceID()
logData.TraceContext = traceContext
@@ -209,7 +210,7 @@ func (h *Trace) Flush(duration int64, process api.ProcessInterface, traffic *bas
Reason: h.Type,
Status: h.Response.Original().StatusCode,
}
- if traffic.Role == events.ConnectionRoleClient {
+ if traffic.Role == enums.ConnectionRoleClient {
body.ClientProcess = &SamplingTraceLogProcess{ProcessID: process.ID()}
body.ServerProcess = NewHTTP1SampledTraceLogRemoteProcess(traffic, process)
} else {
@@ -278,7 +279,7 @@ func (h *Trace) appendHTTPEvent(attaches []*v3.SpanAttachedEvent, process api.Pr
TraceId: h.Trace.TraceID(),
TraceSegmentId: h.Trace.TraceSegmentID(),
SpanId: h.Trace.SpanID(),
- Type: h.Trace.Provider().Type,
+ Type: h.Trace.Provider().SpanAttachType,
}
return append(attaches, event)
}
@@ -290,12 +291,12 @@ func (h *Trace) appendSyscallEvents(attachEvents []*v3.SpanAttachedEvent, proces
dataIDCache := make(map[uint64]bool)
for e := headerDetails.Front(); e != nil; e = e.Next() {
event := e.Value.(*events.SocketDetailEvent)
- dataIDCache[event.DataID] = true
+ dataIDCache[event.DataID()] = true
attachEvents = h.appendPerDetailEvent(attachEvents, process, traffic, event, message.HeaderBuffer())
}
for e := bodyDetails.Front(); e != nil; e = e.Next() {
event := e.Value.(*events.SocketDetailEvent)
- if dataIDCache[event.DataID] {
+ if dataIDCache[event.DataID()] {
continue
}
attachEvents = h.appendPerDetailEvent(attachEvents, process, traffic, event, message.BodyBuffer())
@@ -306,7 +307,7 @@ func (h *Trace) appendSyscallEvents(attachEvents []*v3.SpanAttachedEvent, proces
func (h *Trace) appendPerDetailEvent(attaches []*v3.SpanAttachedEvent, process api.ProcessInterface, _ *base.ProcessTraffic,
detail *events.SocketDetailEvent, buf *buffer.Buffer) []*v3.SpanAttachedEvent {
event := &v3.SpanAttachedEvent{}
- dataBuffer := buf.FindFirstDataBuffer(detail.DataID)
+ dataBuffer := buf.FindFirstDataBuffer(detail.DataID())
if dataBuffer == nil {
return attaches
}
@@ -336,7 +337,7 @@ func (h *Trace) appendPerDetailEvent(attaches []*v3.SpanAttachedEvent, process a
TraceId: h.Trace.TraceID(),
TraceSegmentId: h.Trace.TraceSegmentID(),
SpanId: h.Trace.SpanID(),
- Type: h.Trace.Provider().Type,
+ Type: h.Trace.Provider().SpanAttachType,
}
return append(attaches, event)
}
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/reader.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/reader.go
index 32d5fa1..e4aac3f 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/reader.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/reader.go
@@ -28,12 +28,10 @@ import (
"strings"
"github.com/apache/skywalking-rover/pkg/logger"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"golang.org/x/net/html/charset"
-
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
)
var (
@@ -103,7 +101,7 @@ func (m *MessageOpt) EndTime() uint64 {
return m.BodyBuffer().LastSocketBuffer().EndTime()
}
-func (m *MessageOpt) Direction() events.SocketDataDirection {
+func (m *MessageOpt) Direction() enums.SocketDataDirection {
return m.HeaderBuffer().FirstSocketBuffer().Direction()
}
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/request.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/request.go
index 9990414..8791611 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/request.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/request.go
@@ -25,8 +25,8 @@ import (
"net/url"
"strings"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
type Request struct {
@@ -56,7 +56,7 @@ func (r *Request) Original() *http.Request {
return r.original
}
-//nolint
+// nolint
func ReadRequest(buf *buffer.Buffer, readBody bool) (*Request, enums.ParseResult, error) {
bufReader := bufio.NewReader(buf)
tp := textproto.NewReader(bufReader)
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/response.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/response.go
index fd13c34..966edb8 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/response.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader/response.go
@@ -25,8 +25,8 @@ import (
"strconv"
"strings"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/buffer"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/enums"
+ "github.com/apache/skywalking-rover/pkg/tools/buffer"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
)
type Response struct {
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/http1/sampling.go b/pkg/profiling/task/network/analyze/layer7/protocols/http1/sampling.go
index ae26d50..efd9f93 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/http1/sampling.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/http1/sampling.go
@@ -28,9 +28,9 @@ import (
"github.com/apache/skywalking-rover/pkg/process/api"
profiling "github.com/apache/skywalking-rover/pkg/profiling/task/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/base"
- protocol "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/http1/reader"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/metrics"
+ protocol "github.com/apache/skywalking-rover/pkg/tools/tracing"
)
const (
diff --git a/pkg/profiling/task/network/analyze/layer7/protocols/protocols.go b/pkg/profiling/task/network/analyze/layer7/protocols/protocols.go
index 8dbe6c1..f26826b 100644
--- a/pkg/profiling/task/network/analyze/layer7/protocols/protocols.go
+++ b/pkg/profiling/task/network/analyze/layer7/protocols/protocols.go
@@ -24,6 +24,7 @@ import (
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
protocol "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/base"
"github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/layer7/protocols/http1"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"golang.org/x/net/context"
)
@@ -46,11 +47,11 @@ func init() {
type Analyzer struct {
ctx protocol.Context
- protocols map[events.ConnectionProtocol]*protocol.ProtocolAnalyzer
+ protocols map[enums.ConnectionProtocol]*protocol.ProtocolAnalyzer
}
func NewAnalyzer(ctx protocol.Context, config *profiling.TaskConfig) *Analyzer {
- protocols := make(map[events.ConnectionProtocol]*protocol.ProtocolAnalyzer)
+ protocols := make(map[enums.ConnectionProtocol]*protocol.ProtocolAnalyzer)
for _, r := range registerProtocols {
p := r()
p.Init(config)
@@ -102,18 +103,18 @@ func (a *Analyzer) ReceiveSocketClose(event *events.SocketCloseEvent) {
}
type ProtocolMetrics struct {
- data map[events.ConnectionProtocol]protocol.Metrics
+ data map[enums.ConnectionProtocol]protocol.Metrics
}
func NewProtocolMetrics() *ProtocolMetrics {
- metrics := make(map[events.ConnectionProtocol]protocol.Metrics)
+ metrics := make(map[enums.ConnectionProtocol]protocol.Metrics)
for _, p := range defaultInstances {
metrics[p.Protocol()] = p.GenerateMetrics()
}
return &ProtocolMetrics{data: metrics}
}
-func (m *ProtocolMetrics) GetProtocolMetrics(p events.ConnectionProtocol) protocol.Metrics {
+func (m *ProtocolMetrics) GetProtocolMetrics(p enums.ConnectionProtocol) protocol.Metrics {
return m.data[p]
}
diff --git a/pkg/tools/btf/linker.go b/pkg/tools/btf/linker.go
index 66ef34b..51b7d1b 100644
--- a/pkg/tools/btf/linker.go
+++ b/pkg/tools/btf/linker.go
@@ -132,6 +132,9 @@ func (m *Linker) AddSysCall(call string, enter, exit *ebpf.Program) {
}
func (m *Linker) AddSysCallWithKProbe(call string, linkK LinkFunc, p *ebpf.Program) {
+ if p == nil {
+ return
+ }
kprobe, err := linkK(syscallPrefix+call, p, nil)
if err != nil {
diff --git a/pkg/profiling/task/network/analyze/buffer/buffer.go b/pkg/tools/buffer/buffer.go
similarity index 68%
rename from pkg/profiling/task/network/analyze/buffer/buffer.go
rename to pkg/tools/buffer/buffer.go
index 8b5ed98..45e518d 100644
--- a/pkg/profiling/task/network/analyze/buffer/buffer.go
+++ b/pkg/tools/buffer/buffer.go
@@ -20,12 +20,11 @@ package buffer
import (
"container/list"
"errors"
- "fmt"
"io"
"sync"
"time"
- "github.com/apache/skywalking-rover/pkg/profiling/task/network/analyze/events"
+ "github.com/apache/skywalking-rover/pkg/tools/enums"
"github.com/apache/skywalking-rover/pkg/tools/host"
)
@@ -33,6 +32,41 @@ var (
ErrNotComplete = errors.New("socket: not complete event")
)
+type SocketDataBuffer interface {
+ // GenerateConnectionID for identity the buffer belong which connection
+ GenerateConnectionID() string
+ // BufferData of the buffer
+ BufferData() []byte
+ // TotalSize of socket data, the data may exceed the size of the BufferData()
+ TotalSize() uint64
+ // Direction of the data, send or receive
+ Direction() enums.SocketDataDirection
+ // BufferStartPosition the buffer start index
+ BufferStartPosition() int
+ // BufferLen the buffer data length
+ BufferLen() int
+ // DataID data id of the buffer
+ DataID() uint64
+ // DataSequence the data sequence under same data id
+ DataSequence() int
+ // IsStart this buffer is start of the same data id
+ IsStart() bool
+ // IsFinished this buffer is finish of the same data id
+ IsFinished() bool
+ // HaveReduceDataAfterChunk check have reduced data after current buffer
+ HaveReduceDataAfterChunk() bool
+
+ // StartTime the data start timestamp
+ StartTime() uint64
+ // EndTime the data end timestamp
+ EndTime() uint64
+}
+
+type SocketDataDetail interface {
+ // DataID data id of the buffer
+ DataID() uint64
+}
+
type Buffer struct {
dataEvents *list.List
detailEvents *list.List
@@ -48,6 +82,24 @@ type Buffer struct {
latestExpiredDataID uint64
}
+type SocketDataEventLimited struct {
+ SocketDataBuffer
+ From int
+ Size int
+}
+
+func (s *SocketDataEventLimited) BufferData() []byte {
+ return s.SocketDataBuffer.BufferData()[s.From:s.Size]
+}
+
+func (s *SocketDataEventLimited) BufferLen() int {
+ return s.Size - s.From
+}
+
+func (s *SocketDataEventLimited) BufferStartPosition() int {
+ return s.From
+}
+
type Position struct {
// element of the event list
element *list.Element
@@ -55,10 +107,16 @@ type Position struct {
bufIndex int
}
-func (p *Position) String() string {
- buffer := p.element.Value.(events.SocketDataBuffer)
- return fmt.Sprintf("data id: %d, sequence: %d, buffer index: %d",
- buffer.DataID(), buffer.DataSequence(), p.bufIndex)
+func (p *Position) Clone() *Position {
+ return &Position{element: p.element, bufIndex: p.bufIndex}
+}
+
+func (p *Position) DataID() uint64 {
+ return p.element.Value.(SocketDataBuffer).DataID()
+}
+
+func (p *Position) Seq() int {
+ return p.element.Value.(SocketDataBuffer).DataSequence()
}
func NewBuffer() *Buffer {
@@ -69,9 +127,9 @@ func NewBuffer() *Buffer {
}
}
-func (r *Buffer) FindFirstDataBuffer(dataID uint64) events.SocketDataBuffer {
+func (r *Buffer) FindFirstDataBuffer(dataID uint64) SocketDataBuffer {
for e := r.dataEvents.Front(); e != nil; e = e.Next() {
- cur := e.Value.(events.SocketDataBuffer)
+ cur := e.Value.(SocketDataBuffer)
if cur.DataID() == dataID {
return cur
}
@@ -83,6 +141,16 @@ func (r *Buffer) Position() *Position {
return r.current.Clone()
}
+func (r *Buffer) Clean() {
+ r.eventLocker.Lock()
+ defer r.eventLocker.Unlock()
+
+ r.dataEvents = list.New()
+ r.detailEvents = list.New()
+ r.head = nil
+ r.current = nil
+}
+
func (r *Buffer) Slice(validated bool, start, end *Position) *Buffer {
dataEvents := list.New()
detailEvents := list.New()
@@ -91,7 +159,7 @@ func (r *Buffer) Slice(validated bool, start, end *Position) *Buffer {
// found first matches detail event
if detailEvents.Len() == 0 || firstDetailElement == nil {
for e := r.detailEvents.Front(); e != nil; e = e.Next() {
- if e.Value.(*events.SocketDetailEvent).DataID >= nextElement.Value.(events.SocketDataBuffer).DataID() {
+ if e.Value.(SocketDataDetail).DataID() >= nextElement.Value.(SocketDataBuffer).DataID() {
detailEvents.PushBack(e.Value)
firstDetailElement = e
break
@@ -100,20 +168,20 @@ func (r *Buffer) Slice(validated bool, start, end *Position) *Buffer {
}
dataEvents.PushBack(nextElement.Value)
}
- lastBuffer := end.element.Value.(events.SocketDataBuffer)
- dataEvents.PushBack(&events.SocketDataEventLimited{SocketDataBuffer: lastBuffer, Size: end.bufIndex})
+ lastBuffer := end.element.Value.(SocketDataBuffer)
+ dataEvents.PushBack(&SocketDataEventLimited{SocketDataBuffer: lastBuffer, Size: end.bufIndex})
// if the first detail element been found, append the details until the last buffer data id
if firstDetailElement == nil {
for e := r.detailEvents.Front(); e != nil; e = e.Next() {
- if e.Value.(*events.SocketDetailEvent).DataID == lastBuffer.DataID() {
+ if e.Value.(SocketDataDetail).DataID() == lastBuffer.DataID() {
detailEvents.PushBack(e.Value)
break
}
}
- } else if firstDetailElement != nil && firstDetailElement.Value.(*events.SocketDetailEvent).DataID != lastBuffer.DataID() {
+ } else if firstDetailElement != nil && firstDetailElement.Value.(SocketDataDetail).DataID() != lastBuffer.DataID() {
for tmp := firstDetailElement.Next(); tmp != nil; tmp = tmp.Next() {
- if tmp.Value.(*events.SocketDetailEvent).DataID > lastBuffer.DataID() {
+ if tmp.Value.(SocketDataDetail).DataID() > lastBuffer.DataID() {
break
}
detailEvents.PushBack(tmp.Value)
@@ -136,7 +204,7 @@ func (r *Buffer) Len() int {
var result int
var startIndex = r.head.bufIndex
for e := r.head.element; e != nil; e = e.Next() {
- result += r.head.element.Value.(events.SocketDataBuffer).BufferLen() - startIndex
+ result += r.head.element.Value.(SocketDataBuffer).BufferLen() - startIndex
startIndex = 0
}
return result
@@ -146,18 +214,43 @@ func (r *Buffer) Details() *list.List {
return r.detailEvents
}
-func (r *Buffer) FirstSocketBuffer() events.SocketDataBuffer {
+func (r *Buffer) DataSize() int64 {
+ var result int64
+ var headPosition = r.head
+ if headPosition == nil {
+ if !r.PrepareForReading() {
+ return 0
+ }
+ defer func() {
+ r.ResetForLoopReading()
+ }()
+ headPosition = r.head
+ }
+
+ isFirst := true
+ for e := headPosition.element; e != nil; e = e.Next() {
+ if isFirst {
+ result += int64(e.Value.(SocketDataBuffer).BufferLen() - headPosition.bufIndex)
+ isFirst = false
+ } else {
+ result += int64(e.Value.(SocketDataBuffer).BufferLen())
+ }
+ }
+ return result
+}
+
+func (r *Buffer) FirstSocketBuffer() SocketDataBuffer {
if r.dataEvents.Len() == 0 {
return nil
}
- return r.dataEvents.Front().Value.(events.SocketDataBuffer)
+ return r.dataEvents.Front().Value.(SocketDataBuffer)
}
-func (r *Buffer) LastSocketBuffer() events.SocketDataBuffer {
+func (r *Buffer) LastSocketBuffer() SocketDataBuffer {
if r.dataEvents.Len() == 0 {
return nil
}
- return r.dataEvents.Back().Value.(events.SocketDataBuffer)
+ return r.dataEvents.Back().Value.(SocketDataBuffer)
}
// DetectNotSendingLastPosition detect the buffer contains not sending data: the BPF limited socket data count
@@ -167,7 +260,7 @@ func (r *Buffer) DetectNotSendingLastPosition() *Position {
}
for e := r.dataEvents.Front(); e != nil; e = e.Next() {
- buf := e.Value.(events.SocketDataBuffer)
+ buf := e.Value.(SocketDataBuffer)
// the buffer is sent finished but still have reduced data not send
if buf.IsFinished() && buf.HaveReduceDataAfterChunk() {
return &Position{element: e, bufIndex: buf.BufferLen()}
@@ -186,9 +279,12 @@ func CombineSlices(validated bool, buffers ...*Buffer) *Buffer {
dataEvents := list.New()
detailEvents := list.New()
for _, b := range buffers {
+ if b == nil {
+ continue
+ }
if b.head.bufIndex > 0 {
- headBuffer := b.dataEvents.Front().Value.(events.SocketDataBuffer)
- dataEvents.PushBack(&events.SocketDataEventLimited{SocketDataBuffer: headBuffer,
+ headBuffer := b.dataEvents.Front().Value.(SocketDataBuffer)
+ dataEvents.PushBack(&SocketDataEventLimited{SocketDataBuffer: headBuffer,
From: b.head.bufIndex, Size: headBuffer.BufferLen()})
for next := b.dataEvents.Front().Next(); next != nil; next = next.Next() {
dataEvents.PushBack(next.Value)
@@ -244,7 +340,7 @@ func (r *Buffer) OffsetPosition(offset int) *Position {
var curIndex = r.current.bufIndex
for ; curEle != nil; curEle = nextElement(curEle) {
nextOffset := curIndex + offset
- bufferLen := curEle.Value.(events.SocketDataBuffer).BufferLen()
+ bufferLen := curEle.Value.(SocketDataBuffer).BufferLen()
if nextOffset >= 0 && nextOffset < bufferLen {
curIndex += offset
break
@@ -260,7 +356,7 @@ func (r *Buffer) OffsetPosition(offset int) *Position {
curEle = next
break
}
- curIndex = curEle.Value.(events.SocketDataBuffer).BufferLen()
+ curIndex = curEle.Value.(SocketDataBuffer).BufferLen()
}
}
@@ -282,12 +378,12 @@ func (r *Buffer) Read(p []byte) (n int, err error) {
return n, nil
}
- curEvent := element.Value.(events.SocketDataBuffer)
+ curEvent := element.Value.(SocketDataBuffer)
next := r.nextElement(element)
if next == nil {
return 0, io.EOF
}
- nextEvent := next.Value.(events.SocketDataBuffer)
+ nextEvent := next.Value.(SocketDataBuffer)
var shouldRead = false
if r.validated {
@@ -311,7 +407,7 @@ func (r *Buffer) Read(p []byte) (n int, err error) {
func (r *Buffer) ReadFromCurrent(p []byte) (element *list.Element, n int) {
element = r.current.element
- curEvent := element.Value.(events.SocketDataBuffer)
+ curEvent := element.Value.(SocketDataBuffer)
residueSize := curEvent.BufferLen() - r.current.bufIndex
if residueSize > 0 {
readLen := len(p)
@@ -326,23 +422,37 @@ func (r *Buffer) ReadFromCurrent(p []byte) (element *list.Element, n int) {
return element, 0
}
+func (r *Buffer) ReadUntilBufferFull(data []byte) error {
+ reduceLen := len(data)
+ currentIndex := 0
+ for reduceLen > 0 {
+ readCount, err := r.Read(data[:reduceLen])
+ if err != nil {
+ return err
+ }
+ reduceLen -= readCount
+ currentIndex += readCount
+ }
+ return nil
+}
+
func (r *Buffer) Merge(other *Buffer) {
if other == nil {
return
}
for e := other.dataEvents.Front(); e != nil; e = e.Next() {
- if v, ok := e.Value.(*events.SocketDataUploadEvent); ok && v != nil {
+ if v, ok := e.Value.(SocketDataBuffer); ok && v != nil {
r.AppendDataEvent(v)
}
}
for e := other.detailEvents.Front(); e != nil; e = e.Next() {
- if v, ok := e.Value.(*events.SocketDetailEvent); ok && v != nil {
+ if v, ok := e.Value.(SocketDataDetail); ok && v != nil {
r.AppendDetailEvent(v)
}
}
}
-func (r *Buffer) read0(currentElement *list.Element, currentBuffer events.SocketDataBuffer, p []byte) (n int, err error) {
+func (r *Buffer) read0(currentElement *list.Element, currentBuffer SocketDataBuffer, p []byte) (n int, err error) {
readLen := len(p)
if currentBuffer.BufferLen() < readLen {
readLen = currentBuffer.BufferLen()
@@ -356,7 +466,7 @@ func (r *Buffer) read0(currentElement *list.Element, currentBuffer events.Socket
// IsCurrentPacketReadFinished means to validate the current reading package is reading finished
func (r *Buffer) IsCurrentPacketReadFinished() bool {
- return r.current.bufIndex == r.current.element.Value.(events.SocketDataBuffer).BufferLen()
+ return r.current.bufIndex == r.current.element.Value.(SocketDataBuffer).BufferLen()
}
func (r *Buffer) ResetForLoopReading() {
@@ -382,20 +492,26 @@ func (r *Buffer) PrepareForReading() bool {
return true
}
+// nolint
func (r *Buffer) RemoveReadElements() bool {
r.eventLocker.Lock()
defer r.eventLocker.Unlock()
// delete until the last data id
if r.head.element != nil && r.current.element != nil {
- firstDataID := r.head.element.Value.(events.SocketDataBuffer).DataID()
- lastDataID := r.current.element.Value.(events.SocketDataBuffer).DataID()
+ firstDataID := r.head.element.Value.(SocketDataBuffer).DataID()
+ currentBuffer := r.current.element.Value.(SocketDataBuffer)
+ lastDataID := currentBuffer.DataID()
startDelete := false
for e := r.detailEvents.Front(); e != nil; {
- event := e.Value.(*events.SocketDetailEvent)
- if !startDelete && event.DataID >= firstDataID && event.DataID <= lastDataID {
+ event := e.Value.(SocketDataDetail)
+ if firstDataID == lastDataID && currentBuffer.BufferLen() != r.current.bufIndex {
+ // current buffer is not finished, so the detail cannot be deleted
+ break
+ }
+ if !startDelete && event.DataID() >= firstDataID && event.DataID() <= lastDataID {
startDelete = true
- } else if startDelete && event.DataID > lastDataID {
+ } else if startDelete && event.DataID() > lastDataID {
// out of the data id, just break
break
}
@@ -412,17 +528,25 @@ func (r *Buffer) RemoveReadElements() bool {
... 433 lines suppressed ...