diff options
| author | Yang Wei <[email protected]> | 2022-01-09 23:41:39 +0800 |
|---|---|---|
| committer | Yang Wei <[email protected]> | 2022-01-09 23:41:39 +0800 |
| commit | 0ddb0cf9d563d9abfd3d13be2888d54d19ac9c54 (patch) | |
| tree | 4d8c4f5d27cfe1a29275676185b3764e99e52f14 /SOURCE | |
| parent | a2108822a3ff0a0768b26a97686f03effb33ca19 (diff) | |
diagnose-tools:增加tcp-connect功能,用于记录tcp主动、被动打开、关闭等信息
Diffstat (limited to 'SOURCE')
| -rw-r--r-- | SOURCE/diagnose-tools/internal.h | 1 | ||||
| -rw-r--r-- | SOURCE/diagnose-tools/main.cc | 1 | ||||
| -rw-r--r-- | SOURCE/diagnose-tools/tcp_connect.cc | 329 | ||||
| -rwxr-xr-x | SOURCE/module/Makefile | 2 | ||||
| -rw-r--r-- | SOURCE/module/chr_dev.c | 3 | ||||
| -rw-r--r-- | SOURCE/module/entry.c | 8 | ||||
| -rwxr-xr-x | SOURCE/module/internal.h | 2 | ||||
| -rwxr-xr-x | SOURCE/module/kernel/throttle_delay.c | 8 | ||||
| -rwxr-xr-x | SOURCE/module/net/net_entry.c | 7 | ||||
| -rw-r--r-- | SOURCE/module/net/net_internal.h | 2 | ||||
| -rw-r--r-- | SOURCE/module/net/tcp_connect.c | 365 | ||||
| -rw-r--r-- | SOURCE/uapi/ali_diagnose.h | 14 | ||||
| -rw-r--r-- | SOURCE/uapi/tcp_connect.h | 53 |
13 files changed, 788 insertions, 7 deletions
diff --git a/SOURCE/diagnose-tools/internal.h b/SOURCE/diagnose-tools/internal.h index 924ec39..c786a39 100644 --- a/SOURCE/diagnose-tools/internal.h +++ b/SOURCE/diagnose-tools/internal.h @@ -31,6 +31,7 @@ int exit_monitor_main(int argc, char **argv); int utilization_main(int argc, char **argv); int perf_main(int argc, char **argv); int tcp_retrans_main(int argc, char **argv); +int tcp_connect_main(int argc, char **argv); int rw_top_main(int argc, char **argv); int irq_delay_main(int argc, char **argv); int mutex_monitor_main(int argc, char **argv); diff --git a/SOURCE/diagnose-tools/main.cc b/SOURCE/diagnose-tools/main.cc index e6c3486..ffd48bd 100644 --- a/SOURCE/diagnose-tools/main.cc +++ b/SOURCE/diagnose-tools/main.cc @@ -228,6 +228,7 @@ static struct diagnose_func all_funcs[] { {"ping-delay6", ping_delay6_main, 0}, {"uprobe", uprobe_main, 0}, {"memcg-stats", memcg_stats_main, 0}, + {"tcp-connect", tcp_connect_main, 0}, {"--vmsize", no_vmsize, 1}, {"-V", report_version, 0}, {"-v", report_version, 0}, diff --git a/SOURCE/diagnose-tools/tcp_connect.cc b/SOURCE/diagnose-tools/tcp_connect.cc new file mode 100644 index 0000000..01892fa --- /dev/null +++ b/SOURCE/diagnose-tools/tcp_connect.cc @@ -0,0 +1,329 @@ +/* + * Linux内核诊断工具--用户态tcp-connect功能实现 + * + * Copyright (C) 2022 Alibaba Ltd. + * + * 作者: Yang Wei <[email protected]> + * + * License terms: GNU General Public License (GPL) version 3 + * + */ + +#include <sched.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <getopt.h> + +#include <sys/time.h> +#include <string.h> +#include <stdio.h> /* for printf */ +#include <stdlib.h> /* for exit */ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <iostream> +#include <fstream> + +#include "internal.h" +#include "symbol.h" +#include "uapi/tcp_connect.h" +#include "params_parse.h" +#include "params_parse.h" + +using namespace std; + +static int tcp_connect_ignore = 0; +static char sls_file[256]; +static int syslog_enabled; + +void usage_tcp_connect(void) +{ + printf(" tcp-connect usage:\n"); + printf(" --help tcp-connect help info\n"); + printf(" --activate\n"); + printf(" verbose VERBOSE\n"); + printf(" --deactivate\n"); + printf(" --report dump log with text.\n"); + printf(" --log\n"); + printf(" sls=/tmp/1.log store in file\n"); + printf(" syslog=1 store in syslog\n"); +} + +static void do_activate(const char *arg) +{ + int ret = 0; + struct params_parser parse(arg); + struct diag_tcp_connect_settings settings; + string str; + + memset(&settings, 0, sizeof(struct diag_tcp_connect_settings)); + + settings.verbose = parse.int_value("verbose"); + + if (run_in_host) { + ret = diag_call_ioctl(DIAG_IOCTL_TCP_CONNECT_SET, (long)&settings); + } else { + ret = -ENOSYS; + syscall(DIAG_TCP_CONNECT_SET, &ret, &settings, sizeof(struct diag_tcp_connect_settings)); + } + + printf("功能设置%s,返回值:%d\n", ret ? "失败" : "成功", ret); + printf(" 输出级别:%d\n", settings.verbose); + + if (ret) + return; + + ret = diag_activate("tcp-connect"); + if (ret == 1) { + printf("tcp-connect activated\n"); + } else { + printf("tcp-connect is not activated, ret %d\n", ret); + } +} + +static void do_deactivate(void) +{ + int ret = 0; + + ret = diag_deactivate("tcp-connect"); + if (ret == 0) { + printf("tcp-connect is not activated\n"); + } else { + printf("deactivate tcp-connect fail, ret is %d\n", ret); + } +} + +static void print_settings_in_json(struct diag_tcp_connect_settings *settings, int ret) +{ + Json::Value root; + std::string str_log; + + if (ret == 0) { + root["activated"] = Json::Value(settings->activated); + root["verbose"] = Json::Value(settings->verbose); + } else { + root["err"] = Json::Value("found tcp-connect settings failed, please check if diagnose-tools is installed correctly or not."); + } + + str_log.append(root.toStyledString()); + printf("%s", str_log.c_str()); + + return; +} + +static void do_settings(const char *arg) +{ + struct diag_tcp_connect_settings settings; + int ret; + int enable_json = 0; + struct params_parser parse(arg); + enable_json = parse.int_value("json"); + + memset(&settings, 0, sizeof(struct diag_tcp_connect_settings)); + if (run_in_host) { + ret = diag_call_ioctl(DIAG_IOCTL_TCP_CONNECT_SETTINGS, (long)&settings); + } else { + ret = -ENOSYS; + syscall(DIAG_TCP_CONNECT_SETTINGS, &ret, &settings, sizeof(struct diag_tcp_connect_settings)); + } + + if (1 == enable_json) { + return print_settings_in_json(&settings, ret); + } + + if (ret == 0) { + printf("功能设置:\n"); + printf(" 是否激活:%s\n", settings.activated ? "√" : "×"); + printf(" 输出级别:%d\n", settings.verbose); + } else { + printf("获取tcp-connect设置失败,请确保正确安装了diagnose-tools工具\n"); + } +} + +static int tcp_connect_extract(void *buf, unsigned int len, void *) +{ + int *et_type; + struct tcp_connect_detail *detail; + struct in_addr addr; + + if (len == 0) + return 0; + + et_type = (int *)buf; + switch (*et_type) { + case et_tcp_connect_detail: + if (len < sizeof(struct tcp_connect_detail)) + break; + detail = (struct tcp_connect_detail *)buf; + printf("CGROUP:[%s] comm:%s 时间:[%lu:%lu]\n", detail->cgroup, detail->comm, + detail->tv.tv_sec, detail->tv.tv_usec); + printf("type:%d\n", detail->con_type); + addr.s_addr = detail->laddr; + printf("laddr:%s lport:%d\n", inet_ntoa(addr), detail->lport); + addr.s_addr = detail->raddr; + printf("raddr:%s rport:%d\n", inet_ntoa(addr), detail->rport); + printf("\n"); + break; + default: + break; + } + + return 0; +} + +static int sls_extract(void *buf, unsigned int len, void *) +{ + int *et_type; + struct tcp_connect_detail *detail; + struct in_addr addr; + struct diag_timespec tv; + Json::Value root; + stringstream ss; + + if (len == 0) + return 0; + + diag_gettimeofday(&tv, NULL); + et_type = (int *)buf; + switch (*et_type) { + case et_tcp_connect_detail: + if (len < sizeof(struct tcp_connect_detail)) + break; + detail = (struct tcp_connect_detail *)buf; + root["type"] = Json::Value(detail->con_type); + root["time"] = Json::Value(detail->tv.tv_sec); + addr.s_addr = detail->laddr; + root["laddr"] = Json::Value(inet_ntoa(addr)); + root["lport"] = Json::Value(detail->lport); + addr.s_addr = detail->raddr; + root["raddr"] = Json::Value(inet_ntoa(addr)); + root["rport"] = Json::Value(detail->rport); + root["comm"] = Json::Value(detail->comm); + root["cgroup"] = Json::Value(detail->cgroup); + + write_file(sls_file, "tcp-connect", &tv, 0, 0, root); + write_syslog(syslog_enabled, "tcp-connect", &tv, 0, 0, root); + break; + default: + break; + } + + return 0; +} +static void do_extract(char *buf, int len) +{ + extract_variant_buffer(buf, len, tcp_connect_extract, NULL); +} + +static void do_dump(const char *arg) +{ + static char variant_buf[1024 * 1024]; + int len; + int ret = 0; + struct params_parser parse(arg); + tcp_connect_ignore = parse.int_value("ignore"); + struct diag_ioctl_dump_param dump_param = { + .user_ptr_len = &len, + .user_buf_len = 1024 * 1024, + .user_buf = variant_buf, + }; + + memset(variant_buf, 0, 1024 * 1024); + if (run_in_host) { + ret = diag_call_ioctl(DIAG_IOCTL_TCP_CONNECT_SET_DUMP, (long)&dump_param); + } else { + ret = -ENOSYS; + syscall(DIAG_TCP_CONNECT_DUMP, &ret, &len, variant_buf, 1024 * 1024); + } + + if (ret == 0) { + do_extract(variant_buf, len); + } + + tcp_connect_ignore = 0; +} + +static void do_sls(char *arg) +{ + int ret; + int len; + static char variant_buf[1024 * 1024]; + struct diag_ioctl_dump_param dump_param = { + .user_ptr_len = &len, + .user_buf_len = 1024 * 1024, + .user_buf = variant_buf, + }; + + ret = log_config(arg, sls_file, &syslog_enabled); + if (ret != 1) + return; + + while (1) { + if (run_in_host) { + ret = diag_call_ioctl(DIAG_IOCTL_TCP_CONNECT_SET_DUMP, (long)&dump_param); + } else { + syscall(DIAG_TCP_CONNECT_DUMP, &ret, &len, variant_buf, 1024 * 1024); + } + + if (ret == 0 && len > 0) { + extract_variant_buffer(variant_buf, len, sls_extract, NULL); + } + + sleep(10); + } +} + +int tcp_connect_main(int argc, char **argv) +{ + static struct option long_options[] = { + {"help", no_argument, 0, 0 }, + {"activate", optional_argument, 0, 0 }, + {"deactivate", no_argument, 0, 0 }, + {"settings", optional_argument, 0, 0 }, + {"report", optional_argument, 0, 0 }, + {"log", required_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + int c; + + if (argc <= 1) { + usage_tcp_connect(); + return 0; + } + while (1) { + int option_index = -1; + + c = getopt_long_only(argc, argv, "", long_options, &option_index); + if (c == -1) + break; + switch (option_index) { + case 0: + usage_tcp_connect(); + break; + case 1: + do_activate(optarg ? optarg : ""); + break; + case 2: + do_deactivate(); + break; + case 3: + do_settings(optarg ? optarg : ""); + break; + case 4: + do_dump(optarg ? optarg : ""); + break; + case 5: + do_sls(optarg); + break; + default: + usage_tcp_connect(); + break; + } + } + + return 0; +} diff --git a/SOURCE/module/Makefile b/SOURCE/module/Makefile index 0838616..d6c312a 100755 --- a/SOURCE/module/Makefile +++ b/SOURCE/module/Makefile @@ -220,7 +220,7 @@ ifneq ($(KERNELRELEASE),) $(TARGET)-objs += io/io_entry.o $(TARGET)-objs += fs/fs_entry.o fs/orphan.o fs/shm.o fs/rw_top.o $(TARGET)-objs += net/net_entry.o net/tcp_retrans.o net/drop_packet.o net/ping_delay.o net/ping_delay6.o \ - net/net_bandwidth.o + net/net_bandwidth.o net/tcp_connect.o ifeq ($(EXPERIENTIAL),1) $(TARGET)-objs += test/test.o diff --git a/SOURCE/module/chr_dev.c b/SOURCE/module/chr_dev.c index ef4c1f5..6920cc5 100644 --- a/SOURCE/module/chr_dev.c +++ b/SOURCE/module/chr_dev.c @@ -183,6 +183,9 @@ static long diag_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case DIAG_IOCTL_TYPE_MEMCG_STATS: ret = diag_ioctl_memcg_stats(nr, arg); break; + case DIAG_IOCTL_TYPE_TCP_CONNECT: + ret = diag_ioctl_tcp_connect(nr, arg); + break; default: break; } diff --git a/SOURCE/module/entry.c b/SOURCE/module/entry.c index 1c1fa32..237efb2 100644 --- a/SOURCE/module/entry.c +++ b/SOURCE/module/entry.c @@ -58,6 +58,7 @@ #include "uapi/task_monitor.h" #include "uapi/rw_sem.h" #include "uapi/rss_monitor.h" +#include "uapi/tcp_connect.h" unsigned long diag_timer_period = 10; @@ -179,6 +180,8 @@ static ssize_t controller_file_write(struct diag_trace_file *trace_file, activate_memcg_stats(); } else if (strcmp(func, "throttle-delay") == 0) { activate_throttle_delay(); + } else if (strcmp(func, "tcp-connect") == 0) { + activate_tcp_connect(); } up(&controller_sem); @@ -258,6 +261,8 @@ static ssize_t controller_file_write(struct diag_trace_file *trace_file, deactivate_memcg_stats(); } else if (strcmp(func, "throttle-delay") == 0) { deactivate_throttle_delay(); + } else if (strcmp(func, "tcp-connect") == 0) { + deactivate_tcp_connect(); } up(&controller_sem); @@ -427,6 +432,9 @@ static void diag_cb_sys_enter(void *data, struct pt_regs *regs, long id) } else if (id >= DIAG_BASE_SYSCALL_THROTTLE_DELAY && id < DIAG_BASE_SYSCALL_THROTTLE_DELAY + DIAG_SYSCALL_INTERVAL) { ret = throttle_delay_syscall(regs, id); + } else if (id >= DIAG_BASE_SYSCALL_TCP_CONNECT + && id < DIAG_BASE_SYSCALL_TCP_CONNECT + DIAG_SYSCALL_INTERVAL) { + ret = tcp_connect_syscall(regs, id); } up(&controller_sem); diff --git a/SOURCE/module/internal.h b/SOURCE/module/internal.h index 483605e..801bcd6 100755 --- a/SOURCE/module/internal.h +++ b/SOURCE/module/internal.h @@ -812,6 +812,8 @@ int activate_fs_orphan(void); int deactivate_fs_orphan(void); int activate_net_bandwidth(void); int deactivate_net_bandwidth(void); +int activate_tcp_connect(void); +int deactivate_tcp_connect(void); int perf_syscall(struct pt_regs *regs, long id); diff --git a/SOURCE/module/kernel/throttle_delay.c b/SOURCE/module/kernel/throttle_delay.c index 1b4dc3a..cebb7fa 100755 --- a/SOURCE/module/kernel/throttle_delay.c +++ b/SOURCE/module/kernel/throttle_delay.c @@ -663,11 +663,12 @@ static void jump_init(void) } +#if 0 static int kprobe_dequeue_entity_pre(struct kprobe *p, struct pt_regs *regs) { - struct sched_entity *se = (void *)ORIG_PARAM2(regs); - int *flags = (void *)ORIG_PARAM3(regs); - struct task_struct *task; + //struct sched_entity *se = (void *)ORIG_PARAM2(regs); + //int *flags = (void *)ORIG_PARAM3(regs); + //struct task_struct *task; if (!throttle_delay_settings.activated) return 0; @@ -675,6 +676,7 @@ static int kprobe_dequeue_entity_pre(struct kprobe *p, struct pt_regs *regs) return 0; } +#endif #if KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE static void trace_sched_switch_hit(void *__data, bool preempt, diff --git a/SOURCE/module/net/net_entry.c b/SOURCE/module/net/net_entry.c index 83cb821..1560a5c 100755 --- a/SOURCE/module/net/net_entry.c +++ b/SOURCE/module/net/net_entry.c @@ -76,8 +76,14 @@ int diag_net_init(void) if (ret) goto out_net_bandwidth; + ret = diag_net_tcp_connect_init(); + if (ret) + goto out_tcp_connect; + return 0; +out_tcp_connect: + diag_net_net_bandwidth_exit(); out_net_bandwidth: diag_net_ping_delay6_exit(); out_ping_delay6: @@ -106,5 +112,6 @@ void diag_net_exit(void) diag_net_packet_corruption_exit(); diag_net_redis_ixgbe_exit(); diag_net_net_bandwidth_exit(); + diag_net_tcp_connect_exit(); //remove_proc_entry("ali-linux/diagnose/net", NULL); } diff --git a/SOURCE/module/net/net_internal.h b/SOURCE/module/net/net_internal.h index 7285ea9..b5f5305 100644 --- a/SOURCE/module/net/net_internal.h +++ b/SOURCE/module/net/net_internal.h @@ -11,6 +11,8 @@ extern int diag_tcp_retrans_init(void); extern void diag_tcp_retrans_exit(void); +extern int diag_net_tcp_connect_init(void); +extern void diag_net_tcp_connect_exit(void); extern int diag_net_drop_packet_init(void); extern void diag_net_drop_packet_exit(void); extern int diag_net_reqsk_init(void); diff --git a/SOURCE/module/net/tcp_connect.c b/SOURCE/module/net/tcp_connect.c new file mode 100644 index 0000000..13ddae1 --- /dev/null +++ b/SOURCE/module/net/tcp_connect.c @@ -0,0 +1,365 @@ +/* + * Linux内核诊断工具--内核态tcp-connect功能 + * + * Copyright (C) 2022 Alibaba Ltd. + * + * 作者: Yang Wei <[email protected]> + * + * License terms: GNU General Public License (GPL) version 3 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sysctl.h> +#include <linux/rtc.h> +#include <linux/time.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <net/tcp.h> +#include <net/protocol.h> + +#include "uapi/ali_diagnose.h" +#include "uapi/tcp_connect.h" +#include "pub/variant_buffer.h" +#include "pub/kprobe.h" +#include "internal.h" + +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0) + +static struct kprobe kprobe_tcp_connect; +static struct kretprobe kretprobe_inet_csk_accept; +static struct kprobe kprobe_tcp_close; + +static atomic64_t diag_nr_running = ATOMIC64_INIT(0); +static struct diag_variant_buffer tcp_connect_variant_buffer; +static struct diag_tcp_connect_settings tcp_connect_settings; +static unsigned int tcp_connect_alloced; + +static int kprobe_tcp_connect_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct tcp_connect_detail detail; + unsigned long flags; + struct sock *sk; + + atomic64_inc(&diag_nr_running); + + detail.et_type = et_tcp_connect_detail; + detail.con_type = TCPCONNECT; + do_diag_gettimeofday(&detail.tv); + + sk = (struct sock *) ORIG_PARAM1(regs); + detail.raddr = sk->sk_daddr; + detail.laddr = sk->sk_rcv_saddr; + detail.rport = ntohs(sk->sk_dport); + detail.lport = sk->sk_num; + strncpy(detail.comm, current->comm, TASK_COMM_LEN); + detail.comm[TASK_COMM_LEN - 1] = 0; + diag_cgroup_name(current, detail.cgroup, CGROUP_NAME_LEN, 0); + detail.cgroup[CGROUP_NAME_LEN - 1] = 0; + + diag_variant_buffer_spin_lock(&tcp_connect_variant_buffer, flags); + diag_variant_buffer_reserve(&tcp_connect_variant_buffer, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_write_nolock(&tcp_connect_variant_buffer, &detail, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_seal(&tcp_connect_variant_buffer); + diag_variant_buffer_spin_unlock(&tcp_connect_variant_buffer, flags); + + atomic64_dec(&diag_nr_running); + + return 0; +} + +static int kretprobe_inet_csk_accept_return(struct kretprobe_instance *ri, struct pt_regs *regs) +{ + struct tcp_connect_detail detail; + unsigned long flags; + struct sock *sk; + + sk = (struct sock *)regs_return_value(regs); + if (!sk) + return 0; + + atomic64_inc(&diag_nr_running); + + detail.et_type = et_tcp_connect_detail; + detail.con_type = TCPACCEPT; + do_diag_gettimeofday(&detail.tv); + + detail.raddr = sk->sk_daddr; + detail.laddr = sk->sk_rcv_saddr; + detail.rport = ntohs(sk->sk_dport); + detail.lport = sk->sk_num; + + strncpy(detail.comm, current->comm, TASK_COMM_LEN); + detail.comm[TASK_COMM_LEN - 1] = 0; + diag_cgroup_name(current, detail.cgroup, CGROUP_NAME_LEN, 0); + detail.cgroup[CGROUP_NAME_LEN - 1] = 0; + + diag_variant_buffer_spin_lock(&tcp_connect_variant_buffer, flags); + diag_variant_buffer_reserve(&tcp_connect_variant_buffer, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_write_nolock(&tcp_connect_variant_buffer, &detail, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_seal(&tcp_connect_variant_buffer); + diag_variant_buffer_spin_unlock(&tcp_connect_variant_buffer, flags); + + atomic64_dec(&diag_nr_running); + + return 0; +} + +static int kprobe_tcp_close_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct tcp_connect_detail detail; + unsigned long flags; + struct sock *sk; + + atomic64_inc(&diag_nr_running); + + detail.et_type = et_tcp_connect_detail; + detail.con_type = TCPCLOSE; + do_diag_gettimeofday(&detail.tv); + + sk = (struct sock *) ORIG_PARAM1(regs); + detail.raddr = sk->sk_daddr; + detail.laddr = sk->sk_rcv_saddr; + detail.rport = ntohs(sk->sk_dport); + detail.lport = sk->sk_num; + strncpy(detail.comm, current->comm, TASK_COMM_LEN); + detail.comm[TASK_COMM_LEN - 1] = 0; + diag_cgroup_name(current, detail.cgroup, CGROUP_NAME_LEN, 0); + detail.cgroup[CGROUP_NAME_LEN - 1] = 0; + + diag_variant_buffer_spin_lock(&tcp_connect_variant_buffer, flags); + diag_variant_buffer_reserve(&tcp_connect_variant_buffer, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_write_nolock(&tcp_connect_variant_buffer, &detail, sizeof(struct tcp_connect_detail)); + diag_variant_buffer_seal(&tcp_connect_variant_buffer); + diag_variant_buffer_spin_unlock(&tcp_connect_variant_buffer, flags); + + atomic64_dec(&diag_nr_running); + + return 0; +} + +static int __activate_tcp_connect(void) +{ + int ret = 0; + + ret = alloc_diag_variant_buffer(&tcp_connect_variant_buffer); + if (ret) + goto out_variant_buffer; + + tcp_connect_alloced = 1; + + ret = hook_kprobe(&kprobe_tcp_connect, "tcp_connect", + kprobe_tcp_connect_pre, NULL); + if (ret) { + printk("aprof: failed to hook tcp_connect, ret=%d\n", ret); + goto out_variant_buffer;; + } + + ret = hook_kretprobe(&kretprobe_inet_csk_accept, "inet_csk_accept", + NULL, kretprobe_inet_csk_accept_return, 0); + if (ret) { + printk("aprof: failed to hoot inet_csk_accept, ret:%d\n", ret); + goto err_unhook_tcp_connect; + } + + ret = hook_kprobe(&kprobe_tcp_close, "tcp_close", + kprobe_tcp_close_pre, NULL); + if (ret) { + printk("aprof: failed to hoot tcp_close, ret:%d\n", ret); + goto err_unhook_inet_csk_accept; + } + + return 1; + + +err_unhook_inet_csk_accept: + unhook_kretprobe(&kretprobe_inet_csk_accept); +err_unhook_tcp_connect: + unhook_kprobe(&kprobe_tcp_connect); +out_variant_buffer: + return 0; +} + +static void __deactivate_tcp_connect(void) +{ + unhook_kprobe(&kprobe_tcp_connect); + unhook_kretprobe(&kretprobe_inet_csk_accept); + unhook_kprobe(&kprobe_tcp_close); + + synchronize_sched(); + msleep(20); + while (atomic64_read(&diag_nr_running) > 0) + msleep(20); +} + +int activate_tcp_connect(void) +{ + if (!tcp_connect_settings.activated) + tcp_connect_settings.activated = __activate_tcp_connect(); + + return tcp_connect_settings.activated; +} + +int deactivate_tcp_connect(void) +{ + if (tcp_connect_settings.activated) + __deactivate_tcp_connect(); + + tcp_connect_settings.activated = 0; + return 0; +} + +int tcp_connect_syscall(struct pt_regs *regs, long id) +{ + int __user *user_ptr_len; + size_t __user user_buf_len; + void __user *user_buf; + int ret = 0; + struct diag_tcp_connect_settings settings; + + switch (id) { + case DIAG_TCP_CONNECT_SET: + user_buf = (void __user *)SYSCALL_PARAM1(regs); + user_buf_len = (size_t)SYSCALL_PARAM2(regs); + + if (user_buf_len != sizeof(struct diag_tcp_connect_settings)) { + ret = -EINVAL; + } else if (tcp_connect_settings.activated) { + ret = -EBUSY; + } else { + ret = copy_from_user(&settings, user_buf, user_buf_len); + if (!ret) { + tcp_connect_settings = settings; + } + } + break; + case DIAG_TCP_CONNECT_SETTINGS: + user_buf = (void __user *)SYSCALL_PARAM1(regs); + user_buf_len = (size_t)SYSCALL_PARAM2(regs); + + if (user_buf_len != sizeof(struct diag_tcp_connect_settings)) { + ret = -EINVAL; + } else { + settings.activated = tcp_connect_settings.activated; + settings.verbose = tcp_connect_settings.verbose; + ret = copy_to_user(user_buf, &settings, user_buf_len); + } + break; + case DIAG_TCP_CONNECT_DUMP: + user_ptr_len = (void __user *)SYSCALL_PARAM1(regs); + user_buf = (void __user *)SYSCALL_PARAM2(regs); + user_buf_len = (size_t)SYSCALL_PARAM3(regs); + + if (!tcp_connect_alloced) { + ret = -EINVAL; + } else { + ret = copy_to_user_variant_buffer(&tcp_connect_variant_buffer, + user_ptr_len, user_buf, user_buf_len); + record_dump_cmd("tcp-connect"); + } + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +long diag_ioctl_tcp_connect(unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct diag_tcp_connect_settings settings; + struct diag_ioctl_dump_param dump_param; + + switch (cmd) { + case CMD_TCP_CONNECT_SET: + if (tcp_connect_settings.activated) { + ret = -EBUSY; + } else { + ret = copy_from_user(&settings, (void *)arg, sizeof(struct diag_tcp_connect_settings)); + if (!ret) { + tcp_connect_settings = settings; + } + } + break; + case CMD_TCP_CONNECT_SETTINGS: + settings.activated = tcp_connect_settings.activated; + settings.verbose = tcp_connect_settings.verbose; + ret = copy_to_user((void *)arg, &settings, sizeof(struct diag_tcp_connect_settings)); + break; + case CMD_TCP_CONNECT_DUMP: + ret = copy_from_user(&dump_param, (void *)arg, sizeof(struct diag_ioctl_dump_param)); + + if (!tcp_connect_alloced) { + ret = -EINVAL; + } else if (!ret){ + ret = copy_to_user_variant_buffer(&tcp_connect_variant_buffer, + dump_param.user_ptr_len, dump_param.user_buf, dump_param.user_buf_len); + record_dump_cmd("tcp-connect"); + } + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} + +int diag_net_tcp_connect_init(void) +{ + init_diag_variant_buffer(&tcp_connect_variant_buffer, 2 * 1024 * 1024); + + if (tcp_connect_settings.activated) + activate_tcp_connect(); + + return 0; +} + + +void diag_net_tcp_connect_exit(void) +{ + if (tcp_connect_settings.activated) + deactivate_tcp_connect(); + tcp_connect_settings.activated = 0; + + destroy_diag_variant_buffer(&tcp_connect_variant_buffer); + return; +} + +#else + +int diag_net_tcp_connect_init(void) +{ + return 0; +} + +void diag_net_tcp_connect_exit(void) +{ +} + +int activate_tcp_connect(void) +{ + return 0; +} + +int deactivate_tcp_connect(void) +{ + return 0; +} + +int tcp_connect_syscall(struct pt_regs *regs, long id) +{ + return 0; +} + +long diag_ioctl_tcp_connect(unsigned int cmd, unsigned long arg) +{ + return 0; +} + +#endif + diff --git a/SOURCE/uapi/ali_diagnose.h b/SOURCE/uapi/ali_diagnose.h index 3c7a4d6..d5c8cdb 100644 --- a/SOURCE/uapi/ali_diagnose.h +++ b/SOURCE/uapi/ali_diagnose.h @@ -100,6 +100,7 @@ extern unsigned long debug_mode; #define DIAG_IOCTL_TYPE_RSS_MONITOR (DIAG_IOCTL_TYPE_RW_SEM + 1) #define DIAG_IOCTL_TYPE_MEMCG_STATS (DIAG_IOCTL_TYPE_RSS_MONITOR + 1) #define DIAG_IOCTL_TYPE_THROTTLE_DELAY (DIAG_IOCTL_TYPE_MEMCG_STATS + 1) +#define DIAG_IOCTL_TYPE_TCP_CONNECT (DIAG_IOCTL_TYPE_THROTTLE_DELAY + 1) #define DIAG_IOCTL_TYPE_END (DIAG_IOCTL_TYPE_THROTTLE_DELAY + 1) @@ -138,6 +139,7 @@ long diag_ioctl_task_monitor(unsigned int cmd, unsigned long arg); long diag_ioctl_rw_sem(unsigned int cmd, unsigned long arg); long diag_ioctl_rss_monitor(unsigned int cmd, unsigned long arg); long diag_ioctl_memcg_stats(unsigned int cmd, unsigned long arg); +long diag_ioctl_tcp_connect(unsigned int cmd, unsigned long arg); struct diag_ioctl_test { int in; @@ -345,10 +347,13 @@ struct diag_ioctl_dump_param_cycle { #define DIAG_BASE_SYSCALL_MEMCG_STATS \ (DIAG_BASE_SYSCALL_PING_DELAY6 + DIAG_SYSCALL_INTERVAL) -/// 1900 +/// 1950 #define DIAG_BASE_SYSCALL_THROTTLE_DELAY \ - (DIAG_BASE_SYSCALL_PING_DELAY6 + DIAG_SYSCALL_INTERVAL) + (DIAG_BASE_SYSCALL_MEMCG_STATS + DIAG_SYSCALL_INTERVAL) +//2000 +#define DIAG_BASE_SYSCALL_TCP_CONNECT \ + (DIAG_BASE_SYSCALL_THROTTLE_DELAY + DIAG_SYSCALL_INTERVAL) #define DIAG_SYSCALL_END (DIAG_BASE_SYSCALL + DIAG_SYSCALL_INTERVAL * 1000) @@ -518,10 +523,13 @@ enum diag_record_id { et_memcg_stats_summary, et_memcg_stats_detail, - et_throttle_delay_base = et_rss_monitor_base + DIAG_EVENT_TYPE_INTERVAL, + et_throttle_delay_base = et_memcg_stats_base + DIAG_EVENT_TYPE_INTERVAL, et_throttle_delay_dither, et_throttle_delay_rq, + et_tcp_connect_base = et_throttle_delay_base + DIAG_EVENT_TYPE_INTERVAL, + et_tcp_connect_detail, + et_count }; diff --git a/SOURCE/uapi/tcp_connect.h b/SOURCE/uapi/tcp_connect.h new file mode 100644 index 0000000..f1bf1ae --- /dev/null +++ b/SOURCE/uapi/tcp_connect.h @@ -0,0 +1,53 @@ +/* + * Linux内核诊断工具--用户接口API + * + * Copyright (C) 2022 Alibaba Ltd. + * + * 作者: Yang Wei <[email protected]> + * + * License terms: GNU General Public License (GPL) version 3 + * + */ + +#ifndef UAPI_TCP_CONNECT_H +#define UAPI_TCP_CONNECT_H + +#include <linux/ioctl.h> +int tcp_connect_syscall(struct pt_regs *regs, long id); + +#define DIAG_TCP_CONNECT_SET (DIAG_BASE_SYSCALL_TCP_CONNECT) +#define DIAG_TCP_CONNECT_SETTINGS (DIAG_TCP_CONNECT_SET + 1) +#define DIAG_TCP_CONNECT_DUMP (DIAG_TCP_CONNECT_SETTINGS + 1) + +struct diag_tcp_connect_settings { + unsigned int activated; + unsigned int verbose; +}; + +enum connect_type { + TCPCONNECT = 1, + TCPACCEPT = 2, + TCPCLOSE = 3, +}; + +struct tcp_connect_detail { + int et_type; + enum connect_type con_type; + struct diag_timespec tv; + unsigned int laddr; + unsigned int raddr; + unsigned short lport; + unsigned short rport; + char comm[TASK_COMM_LEN]; + char cgroup[CGROUP_NAME_LEN]; +}; + +#define CMD_TCP_CONNECT_SET (0) +#define CMD_TCP_CONNECT_SETTINGS (CMD_TCP_CONNECT_SET + 1) +#define CMD_TCP_CONNECT_DUMP (CMD_TCP_CONNECT_SETTINGS + 1) +#define DIAG_IOCTL_TCP_CONNECT_SET _IOWR(DIAG_IOCTL_TYPE_TCP_CONNECT, CMD_TCP_CONNECT_SET, struct diag_tcp_connect_settings) +#define DIAG_IOCTL_TCP_CONNECT_SETTINGS _IOWR(DIAG_IOCTL_TYPE_TCP_CONNECT, CMD_TCP_CONNECT_SETTINGS, struct diag_tcp_connect_settings) +#define DIAG_IOCTL_TCP_CONNECT_SET_DUMP _IOWR(DIAG_IOCTL_TYPE_TCP_CONNECT, CMD_TCP_CONNECT_DUMP, struct diag_ioctl_dump_param) + +#endif + |
