diff --git a/config/gala-gopher.conf b/config/gala-gopher.conf index c70e9880019a648ed5a5679e1ce0c2ceec76d887..13a110b4bdec641ba0f25508935d9626998b0cae 100644 --- a/config/gala-gopher.conf +++ b/config/gala-gopher.conf @@ -191,6 +191,12 @@ extend_probes = param = ""; switch = "off"; }, + { + name = "httpprobe"; + command = "/opt/gala-gopher/extend_probes/httpprobe" + param = "-t 5"; + switch = "off"; + }, { name = "jvmprobe"; command = "java -classpath $JAVA_HOME/lib/tools.jar:/opt/gala-gopher/extend_probes/ JvmProbe" diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/Makefile b/src/probes/extends/ebpf.probe/src/httpprobe/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ba5eda9a74cee2dd579900db1140fb948098600 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/Makefile @@ -0,0 +1,46 @@ +include ../mk/var.mk +INCLUDES = $(BASE_INC) + +APP := httpprobe + +SRC_CPLUS := $(wildcard *.cpp) +SRC_CPLUS += $(CPLUSFILES) + +BPF_C := $(wildcard *.bpf.c) +DEPS := $(patsubst %.bpf.c, %.bpf.o, $(BPF_C)) +DEPS += $(patsubst %.bpf.c, %.skel.h, $(BPF_C)) +DEPS += $(patsubst %.cpp, %.o, $(SRC_CPLUS)) + +SRC_C := $(filter-out $(BPF_C), $(wildcard *.c)) +SRC_C += $(CFILES) + +.PHONY: all clean install + +all: pre deps app +pre: $(OUTPUT) +deps: $(DEPS) +# build bpf code +%.bpf.o: %.bpf.c + $(CLANG) $(CFLAGS) -target bpf $(INCLUDES) -c $(filter %.c,$^) -o $@ + $(LLVM_STRIP) -g $@ + +# build skel.h +%.skel.h: %.bpf.o + $(BPFTOOL) gen skeleton $< > $@ + +# build c++ files +%.o: %.cpp + $(C++) -c $^ $(CXXFLAGS) $(INCLUDES) -o $@ + +app: $(APP) +%: %.c $(SRC_C) + $(CC) $(CFLAGS) $(patsubst %.cpp, %.o, $(SRC_CPLUS)) $(INCLUDES) $^ $(LDFLAGS) $(LINK_TARGET) -o $@ + @echo $@ "compiling completed." +clean: + rm -rf $(DEPS) + rm -rf $(APP) + +install: + mkdir -p $(INSTALL_DIR) + cp $(APP) $(INSTALL_DIR) + diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.bpf.h b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.bpf.h new file mode 100644 index 0000000000000000000000000000000000000000..232210ade655da3056572dc015043bedb15edaf7 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.bpf.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * gala-gopher licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Ernest + * Create: 2022-08-27 + * Description: include file for *.bpf.c + ******************************************************************************/ +#ifndef __HTTPPROBE_BPF_H +#define __HTTPPROBE_BPF_H + +#pragma once + +#include "httpprobe.h" + +struct conn_key_t { + u32 tgid; + int skfd; +}; + +struct conn_data_t { + u64 sock; + int method; + int status; + u64 recvtime; + u64 ackedtime; +}; + +struct conn_samp_key_t { + struct sock *sk; +}; + +struct conn_samp_data_t { + u32 tgid; + int skfd; + int method; + int status; + u32 endseq; + u64 recvtime; + u64 ackedtime; + u64 longestrtt; + u64 lastreport; +}; + +struct bpf_map_def SEC("maps") conn_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct conn_key_t), + .value_size = sizeof(struct conn_data_t), + .max_entries = MAX_CONN_LEN, +}; + +struct bpf_map_def SEC("maps") conn_samp_map = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(struct conn_samp_key_t), + .value_size = sizeof(struct conn_samp_data_t), + .max_entries = MAX_CONN_LEN, +}; + +static __always_inline int parse_req_method(const char *str) +{ + if (__builtin_memcmp(str, "GET ", 4) == 0) { + return HTTP_GET; + } else if (__builtin_memcmp(str, "HEAD", 4) == 0 && str[4] == ' ') { + return HTTP_HEAD; + } else if (__builtin_memcmp(str, "POST", 4) == 0 && str[4] == ' ') { + return HTTP_POST; + } else if (__builtin_memcmp(str, "PUT ", 4) == 0) { + return HTTP_PUT; + } else if (__builtin_memcmp(str, "DELE", 4) == 0 && __builtin_memcmp(str + 3, "ETE ", 4) == 0) { + return HTTP_DELETE; + } else if (__builtin_memcmp(str, "CONN", 4) == 0 && __builtin_memcmp(str + 4, "ECT ", 4) == 0) { + return HTTP_CONNECT; + } else if (__builtin_memcmp(str, "OPTI", 4) == 0 && __builtin_memcmp(str + 4, "ONS ", 4) == 0) { + return HTTP_OPTIONS; + } else if (__builtin_memcmp(str, "TRAC", 4) == 0 && __builtin_memcmp(str + 2, "ACE ", 4) == 0) { + return HTTP_TRACE; + } else if (__builtin_memcmp(str, "PATC", 4) == 0 && __builtin_memcmp(str + 2, "TCH ", 4) == 0) { + return HTTP_PATCH; + } + return HTTP_UNKNOWN; +} + +#endif \ No newline at end of file diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.c b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.c new file mode 100644 index 0000000000000000000000000000000000000000..4078136147f9d362228f8b20076107a06e2824e2 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.c @@ -0,0 +1,187 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * gala-gopher licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Ernest + * Create: 2022-08-27 + * Description: http probe user prog + ******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf.h" +#include "args.h" +#include "kprobe.skel.h" +#include "sslprobe.skel.h" + +#ifdef BPF_PROG_KERN +#undef BPF_PROG_KERN +#endif + +#ifdef BPF_PROG_USER +#undef BPF_PROG_USER +#endif + +#include "httpprobe.h" + +#define HTTP_SLI_METRIC "http_sli" +#define HTTP_MAX_SLI_METRIC "http_max_sli" +#define NGINX_PATH "which nginx" +#define APACHE_PATH "which httpd" +#define NGINX_SSL_PATH "ldd $(which nginx) | grep libssl | awk '{print $3}'" +#define APACHE_SSL_PATH "ldd /etc/httpd/modules/mod_ssl.so | grep libssl | awk '{print $3}'" + +#define LOAD_HTTP_PROBE(probe_name, end, load) \ + OPEN(probe_name, end, load); \ + MAP_SET_PIN_PATH(probe_name, conn_map, HTTP_CONN_PATH, load); \ + MAP_SET_PIN_PATH(probe_name, conn_samp_map, HTTP_CONN_SAMP_PATH, load); \ + LOAD_ATTACH(probe_name, end, load) + +#define RM_HTTP_PATH "/usr/bin/rm -rf /sys/fs/bpf/probe/__http*" + +#define ATTACH_LIBSSL_FOR(libsslpath, err, success) URETBPF_ATTACH(sslprobe, SSL_read, libsslpath, SSL_read, success); \ + if ((success) <= 0) { \ + fprintf(stderr, "ERROR: attach to tracepoint SSL_read failed\n"); \ + goto err; \ + } \ + URETBPF_ATTACH(sslprobe, SSL_write, libsslpath, SSL_write, success); \ + if ((success) <= 0) { \ + goto err; \ + fprintf(stderr, "ERROR: attach to tracepoint SSL_write failed\n"); \ + } + +static char *methods[HTTP_NUMS] = {"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"}; +static struct probe_params params = { .period = DEFAULT_PERIOD }; + +static void get_libssl_path(char *nginx_sslpath, char *apache_sslpath) +{ + FILE *f1 = NULL, *f2 = NULL; + char buf[PATH_LEN] = {0}; + + f1 = popen(NGINX_PATH, "r"); + if (fgets(buf, PATH_LEN, f1) != NULL && strlen(buf) > 0 && !(buf[strlen(buf) - 1] = 0) && access(buf, F_OK) == 0) { + if ((f2 = popen(NGINX_SSL_PATH, "r")) != NULL && fgets(nginx_sslpath, PATH_LEN, f2) != NULL) { + if (strlen(nginx_sslpath) != 0) { + nginx_sslpath[strlen(nginx_sslpath) - 1] = 0; + } + } + pclose(f2); + } + pclose(f1); + f1 = popen(APACHE_PATH, "r"); + if (fgets(buf, PATH_LEN, f1) != NULL && strlen(buf) > 0 && !(buf[strlen(buf) - 1] = 0) && access(buf, F_OK) == 0) { + if ((f2 = popen(NGINX_SSL_PATH, "r")) != NULL && fgets(apache_sslpath, PATH_LEN, f2) != NULL) { + if (strlen(apache_sslpath) != 0) { + apache_sslpath[strlen(apache_sslpath) - 1] = 0; + } + } + pclose(f2); + } + pclose(f1); + if (strcmp(nginx_sslpath, apache_sslpath) == 0) { + apache_sslpath[0] = '\0'; + } +} + +static void print_http_sli(void *ctx, int cpu, void *data, __u32 size) +{ + struct http_request *req = (struct http_request *)data; + unsigned char ser_ip_str[INET6_ADDRSTRLEN]; + unsigned char cli_ip_str[INET6_ADDRSTRLEN]; + + ip_str(req->conn_info.server_ip_info.family, (unsigned char *)&(req->conn_info.server_ip_info.ipaddr), + ser_ip_str, INET6_ADDRSTRLEN); + ip_str(req->conn_info.client_ip_info.family, (unsigned char *)&(req->conn_info.client_ip_info.ipaddr), + cli_ip_str, INET6_ADDRSTRLEN); + if (req->method == HTTP_UNKNOWN) { + return; + } + (void)fprintf(stdout, "|%s|%u|%d|%s|%s|%s|%hu|%s|%hu|%llu|\n", + HTTP_SLI_METRIC, + req->tgid, + req->skfd, + "HTTP", + methods[req->method - 1], + ser_ip_str, + req->conn_info.server_ip_info.port, + cli_ip_str, + ntohs(req->conn_info.client_ip_info.port), + req->latestrtt); + (void)fprintf(stdout, "|%s|%u|%d|%s|%s|%s|%hu|%s|%hu|%llu|\n", + HTTP_MAX_SLI_METRIC, + req->tgid, + req->skfd, + "HTTP", + methods[req->method - 1], + ser_ip_str, + req->conn_info.server_ip_info.port, + cli_ip_str, + ntohs(req->conn_info.client_ip_info.port), + req->longestrtt); + (void)fflush(stdout); +} + +static void load_args(int args_fd, const struct probe_params* params) +{ + __u32 key = 0; + struct http_args_s args = {0}; + args.period = NS(params->period); + (void)bpf_map_update_elem(args_fd, &key, &args, BPF_ANY); +} + +int main(int argc, char **argv) +{ + int err = 0, success = 0; + char nginx_libsslpath[PATH_LEN] = {0}, apache_libsslpath[PATH_LEN] = {0}; + struct perf_buffer* pb = NULL; + FILE *fp = NULL; + + err = args_parse(argc, argv, ¶ms); + if (err != 0) { + goto err1; + } + printf("arg parse interval time:%us\n", params.period); + + fp = popen(RM_HTTP_PATH, "r"); + if (fp != NULL) { + (void)pclose(fp); + fp = NULL; + } + + get_libssl_path(nginx_libsslpath, apache_libsslpath); + INIT_BPF_APP(httpprobe, EBPF_RLIM_LIMITED); + LOAD_HTTP_PROBE(kprobe, err1, 1); + LOAD_HTTP_PROBE(sslprobe, err2, 1); + load_args(GET_MAP_FD(kprobe, args_map), ¶ms); + if (strlen(nginx_libsslpath) != 0) { + ATTACH_LIBSSL_FOR(nginx_libsslpath, err3, success); + } + if (strlen(apache_libsslpath) != 0) { + ATTACH_LIBSSL_FOR(apache_libsslpath, err3, success); + } + pb = create_pref_buffer(GET_MAP_FD(kprobe, http_events), print_http_sli); + if (pb == NULL) { + fprintf(stderr, "ERROR: create perf buffer failed\n"); + goto err2; + } + poll_pb(pb, params.period * THOUSAND); + perf_buffer__free(pb); +err3: + UNLOAD(sslprobe); +err2: + UNLOAD(kprobe); +err1: + return -1; +} \ No newline at end of file diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.h b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.h new file mode 100644 index 0000000000000000000000000000000000000000..d5e2acd528fb45720520f4c4b397f75f67f34fba --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * gala-gopher licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Ernest + * Create: 2022-08-27 + * Description: include file for *.bpf.c and http probe user prog + ******************************************************************************/ +#ifndef __HTTPPROBE_H +#define __HTTPPROBE_H + +#pragma once + +#include "bpf.h" + +#define METRIC_NAME_HTTP_PROBE "httpprobe" + +#define HTTP_UNKNOWN 0x0 +#define HTTP_GET 0x1 +#define HTTP_HEAD 0x2 +#define HTTP_POST 0x3 +#define HTTP_PUT 0x4 +#define HTTP_DELETE 0x5 +#define HTTP_CONNECT 0x6 +#define HTTP_OPTIONS 0x7 +#define HTTP_TRACE 0x8 +#define HTTP_PATCH 0x9 +#define HTTP_NUMS 0x9 + +#define READY_FOR_UNKNOWN 0x0 +#define READY_FOR_RECVIVE 0x1 +#define READY_FOR_SEND 0x2 +#define READY_FOR_SKBSENT 0x3 +#define READY_FOR_SKBACKED 0x4 + +#define REQ_BUF_SIZE 0x8 +#define MAX_CONN_LEN 0x500 + +#define TGID_LSHIFT_LEN 0x20 + +#if !defined INET_ADDRSTRLEN + #define INET_ADDRSTRLEN 0x4 +#endif + +#define HTTP_CONN_PATH "/sys/fs/bpf/probe/__http_conn" +#define HTTP_CONN_SAMP_PATH "/sys/fs/bpf/probe/__http_conn_samp" + +#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) + +struct http_args_s { + u64 period; +}; + +struct ip { + union { + __u32 ip4; + __u8 ip6[IP6_LEN]; + }; +}; + +struct ip_info_t { + struct ip ipaddr; + __u16 port; + __u32 family; +}; + +struct conn_info_t { + struct ip_info_t server_ip_info; + struct ip_info_t client_ip_info; +}; + +struct http_request { + u32 tgid; + int skfd; + int method; + u64 latestrtt; + u64 longestrtt; + struct conn_info_t conn_info; +}; + +#endif \ No newline at end of file diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.meta b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.meta new file mode 100644 index 0000000000000000000000000000000000000000..7ca06b1094391779fe9c73b77570c98337c29fd8 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/httpprobe.meta @@ -0,0 +1,108 @@ +version = "1.0.0" +measurements: +( + { + table_name: "http_sli", + entity_name: "sli", + fields: + ( + { + description: "the tgid of server process", + type: "key", + name: "tgid", + }, + { + description: "the socket fd of tcp connection", + type: "key", + name: "ins_id", + }, + { + description: "the protocol type", + type: "key", + name: "app", + }, + { + description: "the cmd of req", + type: "key", + name: "method", + }, + { + description: "the IP of server", + type: "label", + name: "server_ip", + }, + { + description: "the port of server", + type: "label", + name: "server_port", + }, + { + description: "the IP of client", + type: "label", + name: "client_ip", + }, + { + description: "the port of client", + type: "label", + name: "client_port", + }, + { + description: "the rtt(ns) of req", + type: "gauge", + name: "rtt_nsec", + } + ) + }, + { + table_name: "http_max_sli", + entity_name: "sli", + fields: + ( + { + description: "the tgid of server process", + type: "key", + name: "tgid", + }, + { + description: "the socket fd of tcp connection", + type: "key", + name: "ins_id", + }, + { + description: "the protocol type", + type: "key", + name: "app", + }, + { + description: "the cmd of req", + type: "key", + name: "method", + }, + { + description: "the IP of server", + type: "label", + name: "server_ip", + }, + { + description: "the port of server", + type: "label", + name: "server_port", + }, + { + description: "the IP of client", + type: "label", + name: "client_ip", + }, + { + description: "the port of client", + type: "label", + name: "client_port", + }, + { + description: "the rtt(ns) of max rtt req", + type: "gauge", + name: "max_rtt_nsec", + } + ) + } +) \ No newline at end of file diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/kprobe.bpf.c b/src/probes/extends/ebpf.probe/src/httpprobe/kprobe.bpf.c new file mode 100644 index 0000000000000000000000000000000000000000..265a8ed2a603fe3d59ecf92a06dce9ca447f5c13 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/kprobe.bpf.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * gala-gopher licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Ernest + * Create: 2022-08-27 + * Description: kernel probe bpf prog for http syscall + ******************************************************************************/ +#ifdef BPF_PROG_USER +#undef BPF_PROG_USER +#endif +#define BPF_PROG_KERN + +#include "httpprobe.bpf.h" + +char g_linsence[] SEC("license") = "GPL"; + +struct bpf_map_def SEC("maps") http_events = { + .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(u32), +}; + +struct bpf_map_def SEC("maps") args_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(struct http_args_s), + .max_entries = 1, +}; + +#ifndef PERIOD +#define PERIOD NS(5) +#endif +static __always_inline u64 get_period() +{ + u32 key = 0; + u64 period = PERIOD; + struct http_args_s *args; + + args = (struct http_args_s *)bpf_map_lookup_elem(&args_map, &key); + if (args) { + period = args->period; + } + return period; +} + +static __always_inline void init_conn_info(struct conn_info_t *conn_info, struct sock *sk) +{ + conn_info->client_ip_info.family = _(sk->sk_family); + if (conn_info->client_ip_info.family == AF_INET) { + conn_info->server_ip_info.ipaddr.ip4 = _(sk->sk_rcv_saddr); + conn_info->client_ip_info.ipaddr.ip4 = _(sk->sk_daddr); + } else if (conn_info->client_ip_info.family == AF_INET6) { + bpf_probe_read(conn_info->server_ip_info.ipaddr.ip6, IP6_LEN, &sk->sk_v6_rcv_saddr); + bpf_probe_read(conn_info->client_ip_info.ipaddr.ip6, IP6_LEN, &sk->sk_v6_daddr); + } else { + return; + } + conn_info->server_ip_info.port = _(sk->sk_num); + conn_info->client_ip_info.port = _(sk->sk_dport); +} + +static __always_inline void periodic_report(struct conn_samp_data_t *data, struct pt_regs *ctx, struct sock *sk) +{ + struct http_request req = {0}; + u64 curr_nano_time = bpf_ktime_get_ns(), period = get_period(); + + if (data->method == HTTP_UNKNOWN) { + return; + } + if (data->ackedtime - data->recvtime > data->longestrtt) { + data->longestrtt = data->ackedtime - data->recvtime; + } + if (curr_nano_time > data->lastreport && curr_nano_time - data->lastreport > period) { + data->lastreport = curr_nano_time; + req.tgid = data->tgid; + req.skfd = data->skfd; + req.method = data->method; + req.latestrtt = data->ackedtime - data->recvtime; + req.longestrtt = data->longestrtt; + init_conn_info(&(req.conn_info), sk); + bpf_perf_event_output(ctx, &http_events, BPF_F_CURRENT_CPU, &req, sizeof(struct http_request)); + } +} + +static __always_inline void handle_req(struct pt_regs *ctx) +{ + char buf[REQ_BUF_SIZE] = {0}; + struct conn_key_t key = {0}; + struct conn_data_t *data = NULL; + struct probe_val val = {0}; + + if (PROBE_GET_PARMS(__sys_recvfrom, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) < REQ_BUF_SIZE) { + bpf_printk("__sys_recvfrom fail..."); + return; + } + key.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN ; + key.skfd = (int)PROBE_PARM1(val); + data = bpf_map_lookup_elem(&conn_map, &key); + if (data == NULL || data->status == READY_FOR_SEND) { + return; + } + bpf_probe_read(buf, REQ_BUF_SIZE, (const char *)PROBE_PARM2(val)); + data->method = parse_req_method(buf); + if (data->method == HTTP_UNKNOWN) { + data->status = READY_FOR_RECVIVE; + return; + } + data->status = READY_FOR_SEND; + data->recvtime = bpf_ktime_get_ns(); +} + +KRETPROBE(__sys_accept4, pt_regs) +{ + int skfd = (int)PT_REGS_RC(ctx); + struct conn_key_t ckey = {0}; + struct conn_data_t cdata = {0}; + struct conn_samp_key_t cskey = {0}; + struct conn_samp_data_t csdata = {0}; + struct task_struct *task_p = (struct task_struct *)bpf_get_current_task(); + + if (skfd < 0) { + bpf_printk("__sys_accept4 fail..."); + return; + } + ckey.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + ckey.skfd = skfd; + cdata.status = READY_FOR_RECVIVE; + cdata.sock = (u64)sock_get_by_fd(ckey.skfd, task_p); + bpf_map_update_elem(&conn_map, &ckey, &cdata, BPF_ANY); + + cskey.sk = (struct sock *)cdata.sock; + csdata.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + csdata.skfd = ckey.skfd; + bpf_map_update_elem(&conn_samp_map, &cskey, &csdata, BPF_ANY); +} + +KPROBE_RET(__sys_recvfrom, pt_regs, CTX_USER) +{ + handle_req(ctx); +} + +KPROBE_RET(ksys_read, pt_regs, CTX_USER) +{ + handle_req(ctx); +} + +KPROBE_RET(__x64_sys_writev, pt_regs, CTX_USER) +{ + struct conn_key_t ckey = {0}; + struct conn_data_t *cdata = NULL; + struct conn_samp_key_t cskey = {0}; + struct conn_samp_data_t *csdata = NULL; + struct probe_val val = {0}; + + if (PROBE_GET_PARMS(__x64_sys_writev, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) <= REQ_BUF_SIZE - 1) { + bpf_printk("__x64_sys_writev fail..."); + return; + } + ckey.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + ckey.skfd = (int)PROBE_PARM2(val); + cdata = (struct conn_data_t *)bpf_map_lookup_elem(&conn_map, &ckey); + if (cdata == NULL || cdata->status == READY_FOR_RECVIVE) { + return; + } + cskey.sk = (struct sock *)cdata->sock; + if (cskey.sk == 0) { + return; + } + csdata = (struct conn_samp_data_t *)bpf_map_lookup_elem(&conn_samp_map, &cskey); + if (csdata == NULL) { + return; + } + csdata->method = cdata->method; + csdata->status = READY_FOR_SKBSENT; + csdata->recvtime = cdata->recvtime; + csdata->endseq = 0; + + cdata->status = READY_FOR_RECVIVE; + cdata->recvtime = 0; + cdata->method = HTTP_UNKNOWN; +} + +KPROBE(tcp_event_new_data_sent, pt_regs) +{ + struct sk_buff *skb_p = NULL; + struct conn_samp_key_t key = {0}; + struct conn_samp_data_t *data = NULL; + + key.sk = (struct sock *)PT_REGS_PARM1(ctx); + skb_p = (struct sk_buff *)PT_REGS_PARM2(ctx); + data = (struct conn_samp_data_t *)bpf_map_lookup_elem(&conn_samp_map, &key); + if (data != NULL && data->status == READY_FOR_SKBSENT) { + data->status = READY_FOR_SKBACKED; + data->endseq = _(TCP_SKB_CB(skb_p)->end_seq); + } +} + +KPROBE(tcp_rate_skb_delivered, pt_regs) +{ + u32 snd_una; + struct tcp_sock *tcp_sk; + struct conn_samp_key_t key = {0}; + struct conn_samp_data_t *data = NULL; + + key.sk = (struct sock *)PT_REGS_PARM1(ctx); + tcp_sk = (struct tcp_sock *)key.sk; + snd_una = _(tcp_sk->snd_una); + data = (struct conn_samp_data_t *)bpf_map_lookup_elem(&conn_samp_map, &key); + if (data != NULL && data->endseq <= snd_una && data->status == READY_FOR_SKBACKED) { + data->status = READY_FOR_UNKNOWN; + data->ackedtime = bpf_ktime_get_ns(); + periodic_report(data, ctx, key.sk); + } +} + +KPROBE(__close_fd, pt_regs) +{ + struct conn_key_t ckey = {0}; + struct conn_data_t *cdata = NULL; + struct conn_samp_key_t cskey = {0}; + struct conn_samp_data_t *csdata = NULL; + + ckey.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + ckey.skfd = (int)PT_REGS_PARM2(ctx); + cdata = bpf_map_lookup_elem(&conn_map, &ckey); + if (cdata != NULL) { + cskey.sk = (struct sock *)cdata->sock; + csdata = bpf_map_lookup_elem(&conn_samp_map, &cskey); + if (csdata != NULL) { + bpf_map_delete_elem(&conn_samp_map, &cskey); + } + bpf_map_delete_elem(&conn_map, &ckey); + } +} \ No newline at end of file diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c b/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c new file mode 100644 index 0000000000000000000000000000000000000000..00e41e8d58af329e74bac9190867e8570391a100 --- /dev/null +++ b/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c @@ -0,0 +1,132 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * gala-gopher licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Ernest + * Create: 2022-08-27 + * Description: sslprobe bpf prog + ******************************************************************************/ +#ifdef BPF_PROG_KERN +#undef BPF_PROG_KERN +#endif +#define BPF_PROG_USER + +#include "httpprobe.bpf.h" + +typedef long (*bio_callback_fn)(void); + +char g_linsence[] SEC("license") = "GPL"; + +enum msg_event_rw_t { + MSG_READ, + MSG_WRITE, +}; + +struct bio_st { + const struct ssl_method_st* method; + bio_callback_fn callback; + bio_callback_fn callback_ex; + char* cb_arg; + int init; + int shutdown; + int flags; + int retry_reason; + int num; +}; + +struct ssl_st { + int version; + const struct ssl_method_st *method; + struct bio_st *rbio; + struct bio_st *wbio; +}; + +static __always_inline int get_fd_from_ssl(const struct ssl_st* ssl_st_p, enum msg_event_rw_t rw_type) +{ + int fd; + + if (ssl_st_p == NULL) { + return -1; + } + struct bio_st *bio_p = (rw_type == MSG_READ) ? _(ssl_st_p->rbio) : _(ssl_st_p->wbio); + if (bio_p == NULL) { + return -1; + } + fd = _(bio_p->num); + return fd; +} + +UPROBE_RET(SSL_read, pt_regs, CTX_USER) +{ + char buf[REQ_BUF_SIZE] = {0}; + struct conn_key_t key = {0}; + struct conn_data_t *data = NULL; + struct probe_val val = {0}; + struct ssl_st* ssl_st_p = NULL; + + if (PROBE_GET_PARMS(SSL_read, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) < REQ_BUF_SIZE) { + bpf_printk("SSL_read fail..."); + return; + } + key.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + ssl_st_p = (struct ssl_st*)PROBE_PARM1(val); + key.skfd = get_fd_from_ssl(ssl_st_p, MSG_READ); + data = bpf_map_lookup_elem(&conn_map, &key); + if (data == NULL || data->status == READY_FOR_SEND) { + return; + } + bpf_probe_read(buf, REQ_BUF_SIZE, (const char *)PROBE_PARM2(val)); + data->method = parse_req_method(buf); + if (data->method == HTTP_UNKNOWN) { + data->status = READY_FOR_RECVIVE; + return; + } + data->status = READY_FOR_SEND; + data->recvtime = bpf_ktime_get_ns(); +} + +UPROBE_RET(SSL_write, pt_regs, CTX_USER) +{ + struct conn_key_t ckey = {0}; + struct conn_data_t *cdata = NULL; + struct conn_samp_key_t cskey = {0}; + struct conn_samp_data_t *csdata = NULL; + struct probe_val val = {0}; + struct ssl_st* ssl_st_p = NULL; + + if (PROBE_GET_PARMS(SSL_write, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) <= REQ_BUF_SIZE - 1) { + bpf_printk("SSL_write fail..."); + return; + } + ckey.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN ; + ssl_st_p = (struct ssl_st*)PROBE_PARM1(val); + ckey.skfd = get_fd_from_ssl(ssl_st_p, MSG_WRITE); + cdata = bpf_map_lookup_elem(&conn_map, &ckey); + if (cdata == NULL || cdata->status == READY_FOR_RECVIVE) { + return; + } + + cskey.sk = (struct sock *)cdata->sock; + if (cskey.sk == 0) { + return; + } + csdata = (struct conn_samp_data_t *)bpf_map_lookup_elem(&conn_samp_map, &cskey); + if (csdata == NULL) { + return; + } + csdata->method = cdata->method; + csdata->status = READY_FOR_SKBSENT; + csdata->recvtime = cdata->recvtime; + csdata->endseq = 0; + + cdata->status = READY_FOR_RECVIVE; + cdata->recvtime = 0; + cdata->method = HTTP_UNKNOWN; + return; +} \ No newline at end of file