diff --git a/MagicEyes/src/visualization/vscode_ext/README.md b/MagicEyes/src/visualization/vscode_ext/README.md index 17cd1fc5f..cc57b0415 100644 --- a/MagicEyes/src/visualization/vscode_ext/README.md +++ b/MagicEyes/src/visualization/vscode_ext/README.md @@ -26,7 +26,7 @@ ![set_token](./images/set_token.png) -设置可视化面板存放路径 +- 设置可视化面板存放路径 > 注意:别忘记面板路径后面加 "/" @@ -40,6 +40,50 @@ ![](./images/error_info.png) +- 设置工具配置文件 + +请将配置文件路径输入在设置中,如`/home/fzy/lmp_tool_ext_config.json`,输入完成后,敲击enter键,程序将根据配置文件中的子系统与工具,生成左侧侧边栏的按钮。 + +配置文件写法参照 `.../MagicEyes/src/visualization/vscode_ext/tool_config_sample/lmp_tool_ext_config.json` + +#### 2.3 如何增加工具 + +配置文件如下。假如有一个工具,名为 mem_checker,输入 memory子系统,则 subsystem_list 不用修改,只需要在内存子系统处增加即可。如果有一个工具,名为 V4L2_tracer,属于 media子系统,则需要在subsystem_list中增加 media 子系统,并在 subsystem 下相应增加,不再赘述。 + +```json +{ + "name" : "lmp_tool_vscode_extension_config", + "version" : "0.0.1", + "subsystem_list" : [ + "CPU", + "memory", + "fs", + "network", + "system_diagnosis", + "hypervisor" + ], + "subsystem" : [ + { + "description" : "Linux CPU子系统观测工具集", + "tools" : [......] + }, + { + "description" : "Linux 内存子系统观测工具集", + "tools" : [ + { + "name": "mem_watcher", + "description" : "内存观测" + }, + { + "name": "mem_checker", + "description" : "内存检查" + } + ] + } +} +``` + + ### 3. 插件开发 #### 3.1 开发 @@ -70,5 +114,12 @@ } ``` +3. 打包vsix + +```bash +# 进入插件开发文件夹 +vsce package +``` + diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json index 957b998e1..967eb2fd8 100644 --- a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/package.json @@ -101,7 +101,13 @@ "default": "/home/fzy/Desktop/panels/", "description": "the default panels search path", "order": 4 - } + }, + "grafana-vscode.default_tool_config_file": { + "type": "string", + "default": "/home/fzy/lmp_tool_ext_config.json", + "description": "the default tool config file", + "order": 5 + } } }, "viewsContainers": { @@ -174,7 +180,7 @@ "@types/uuid": "^9.0.6", "axios": "^1.4.0", "cors": "^2.8.5", - "express": "^4.19.2", + "express": "^4.18.2", "http-proxy": "^1.18.1", "http-proxy-middleware": "^2.0.6", "open": "^8.4.2", diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts index 2b339d898..152b3c7b2 100644 --- a/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts +++ b/MagicEyes/src/visualization/vscode_ext/lmp_ext_vscode/src/extension.ts @@ -10,7 +10,10 @@ import { setVersion } from "./util"; import * as fs from 'fs' // fzy: 为了检查面板文件是否存在 -let default_panel_path = "/home/fzy/Desktop/panels/" // fzy: 为了检查面板文件是否存在 +let default_panel_path = "/home/fzy/Desktop/panels/"; // fzy: 为了检查面板文件是否存在 +let default_tool_config_file = "/home/fzy/lmp_tool_ext_config.json"; +let sub_key = 0; // 子系统计数,用于与element.label进行匹配 + // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -71,7 +74,14 @@ export async function activate(ctx: vscode.ExtensionContext) { default_panel_path = String(settings.get("default_panel_path")); //console.log("path = ", default_panel_path); } - + // fzy, 让用户可以在设置中修改json配置文件放置路径及配置文件名字 + if (event.affectsConfiguration("grafana-vscode.default_tool_config_file")) { + const settings = vscode.workspace.getConfiguration("grafana-vscode"); + default_tool_config_file = String(settings.get("default_tool_config_file")); + //console.log("file = ", default_tool_config_file); + sub_key = 0; // 全局变量先清零,不然 subsystem无法匹配 + TreeViewProvider.initTreeViewItem(); + } }); vscode.commands.registerCommand('grafana-vscode.setPassword', async () => { @@ -97,6 +107,7 @@ export function deactivate() { // --------------------------------------------------------------------------------- // fzy import { CancellationToken, Event, ProviderResult, TreeDataProvider, TreeItem, TreeItemCollapsibleState, window} from "vscode"; +import { json } from "stream/consumers"; // 扩展 TreeItem /* @@ -126,15 +137,26 @@ export class TreeItemNode extends TreeItem { */ export class TreeViewProvider implements TreeDataProvider { + onDidChangeTreeData?: Event | undefined; getTreeItem(element: TreeItem): TreeItem | Thenable { return element; } getChildren(element?: TreeItem | undefined): ProviderResult { + let jsonData: any; // 保存 json 数据 + jsonData = readLmpConfig(); // 读取json配置文件信息 + + let arr: TreeItem[] = new Array(); // treeview 根节点 if (element == undefined) { + for (const key in jsonData.subsystem_list) { + let item: TreeItem = new TreeItem(jsonData.subsystem_list[key], TreeItemCollapsibleState.Expanded); + item.description = jsonData.subsystem[key].description; + arr.push(item); + } + /* let item1: TreeItem = new TreeItem("CPU", TreeItemCollapsibleState.Expanded); item1.description = "Linux CPU子系统观测工具集"; arr.push(item1); @@ -154,11 +176,41 @@ export class TreeViewProvider implements TreeDataProvider { let item5: TreeItem = new TreeItem("hypervisior", TreeItemCollapsibleState.Expanded); item5.description = "Linux 虚拟化子系统工具集"; arr.push(item5); + */ return arr; } // treeview 子节点 else { + //for (let sub_key = 0; sub_key <= 5; sub_key++) { + if (element.label == jsonData.subsystem_list[sub_key]) { // 遍历所有子系统 + //console.log("jsonData.subsystem_list[key] = ", jsonData.subsystem_list[sub_key]); + for (const tool_num in jsonData.subsystem[sub_key].tools) { // 遍历子系统下的所有工具 + let tool_name = jsonData.subsystem[sub_key].tools[tool_num].name; + let tool_description = jsonData.subsystem[sub_key].tools[tool_num].description; + let item1:TreeItem = new TreeItem(tool_name, TreeItemCollapsibleState.None); + item1.description = tool_description; + let tool_command = { + title: tool_name, + command: 'itemClick', + tooltip: "点击将呈现工具的grafana可视化面板", + arguments: [ + tool_name + ] + } + item1.command = tool_command; + arr.push(item1); + } + sub_key++; // key + 1, 匹配下一个子系统 + //console.log("sub_key = ", sub_key); + return arr; + } + else { + return null; + } + } + } + /* if (element.label == 'CPU') { // ***************************************************************************** //let item1: TreeItem = new TreeItem("cpu_watcher", TreeItemCollapsibleState.None); @@ -278,14 +330,42 @@ export class TreeViewProvider implements TreeDataProvider { else { return null; } + } } + */ public static initTreeViewItem(){ const treeViewProvider = new TreeViewProvider(); window.registerTreeDataProvider('lmp_visualization.panel',treeViewProvider); } } + + +export function readLmpConfig() { + let data:any; + if (fs.existsSync(default_tool_config_file)) //判断是否存在此文件 + { + try { + //读取文件内容,并转化为Json对象 + + data = JSON.parse(fs.readFileSync(default_tool_config_file, "utf8")); + // console.log(jsonData); + //获取Json里key为data的数据 + //const data = userBugsJson['data']; + } + catch (error){ + console.error('Error parsing JSON:', error); + } + } + else { + console.error("no config file"); + let config_search_info =" json配置文件不存在,请检查!" + vscode.window.showErrorMessage(config_search_info); + } + return data; +} + // fzy end // --------------------------------------------------------------------------------- diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix b/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix deleted file mode 100644 index 3f2f86320..000000000 Binary files a/MagicEyes/src/visualization/vscode_ext/lmp_grafana-vscode-0.0.16.vsix and /dev/null differ diff --git a/MagicEyes/src/visualization/vscode_ext/lmp_vscode_ext_0.01.vsix b/MagicEyes/src/visualization/vscode_ext/lmp_vscode_ext_0.01.vsix new file mode 100644 index 000000000..9aea7d416 Binary files /dev/null and b/MagicEyes/src/visualization/vscode_ext/lmp_vscode_ext_0.01.vsix differ diff --git a/MagicEyes/src/visualization/vscode_ext/tool_config_sample/lmp_tool_ext_config.json b/MagicEyes/src/visualization/vscode_ext/tool_config_sample/lmp_tool_ext_config.json new file mode 100644 index 000000000..0102d7e69 --- /dev/null +++ b/MagicEyes/src/visualization/vscode_ext/tool_config_sample/lmp_tool_ext_config.json @@ -0,0 +1,80 @@ +{ + "name" : "lmp_tool_vscode_extension_config", + "version" : "0.0.1", + "subsystem_list" : [ + "CPU", + "memory", + "fs", + "network", + "system_diagnosis", + "hypervisor" + ], + "subsystem" : [ + { + "description" : "Linux CPU子系统观测工具集", + "tools" : [ + { + "name": "cpu_watcher", + "description" : "cpu观测" + }, + { + "name": "proc_image", + "description" : "进程画像" + } + ] + }, + { + "description" : "Linux 内存子系统观测工具集", + "tools" : [ + { + "name": "mem_watcher", + "description" : "内存观测" + } + ] + }, + { + "description" : "Linux 文件子系统观测工具集", + "tools" : [ + { + "name": "fast_fuse", + "description" : "FUSE 性能优化" + } + ] + }, + { + "description" : "Linux 网络子系统观测工具集", + "tools" : [ + { + "name": "net_watcher", + "description" : "网络观测" + }, + { + "name": "net_manager", + "description" : "网络优化与加速" + } + ] + }, + { + "description" : "Linux 系统诊断子系统观测工具集", + "tools" : [ + { + "name": "stack_analyzer", + "description" : "栈调用分析器" + } + ] + }, + { + "description" : "Linux 虚拟化子系统观测工具集", + "tools" : [ + { + "name": "kvm_watcher", + "description" : "kvm状态分析" + } + ] + } + ] +} + + + + diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h index e10ec20a4..8d6948e40 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h @@ -62,7 +62,7 @@ struct tcpstate { int newstate; u64 time; }; - +#define MAX_SLOTS 27 enum { e_ip_rcv = 0, e_ip_local_deliver, @@ -111,6 +111,11 @@ struct query_info { u64 start_time; }; +struct hist { + u64 slots[MAX_SLOTS]; + u64 latency; + u64 cnt; +}; // 操作BPF映射的一个辅助函数 static __always_inline void * //__always_inline强制内联 bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { @@ -147,6 +152,11 @@ struct { __uint(max_entries, 256 * 1024); } rb SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rtt_rb SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); @@ -289,13 +299,21 @@ struct { __type(value, struct query_info); } queries SEC(".maps"); +// 定义一个哈希映射,用于存储直方图数据 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256 * 1024); + __type(key, struct ip_packet); + __type(value, struct hist); +} hists SEC(".maps"); + const volatile int filter_dport = 0; const volatile int filter_sport = 0; const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, icmp_info = 0, tcp_info = 0, dns_info = 0, stack_info = 0, mysql_info = 0, - redis_info = 0; + redis_info = 0, rtt_info = 0; /* help macro */ @@ -385,6 +403,25 @@ const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, packet->ack = pkt_tuple.ack; \ packet->seq = pkt_tuple.seq; +#define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) +#define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = val) + +#define INIT_PACKET_TCP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ + .tran_flag = TCP} + +#define INIT_PACKET_UDP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ + .tran_flag = UDP} + /* help macro end */ /* help functions */ @@ -500,11 +537,56 @@ int getstack(void *ctx) { return 0; } -#if KERNEL_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) >= KERNEL_VERSION(6, 3, 1) +#if KERNEL_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) >= \ + KERNEL_VERSION(6, 3, 1) #define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) #else #define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) #endif + +/* +例子: log2(16384) =14 +16384 2进制表示 1000000000000000 +初始值: v=16384 r=0 +1、16384 > 65535 不成立,r=0; v右移动0位 +2、16384 > 255 成立,shift = 8,v右移动8位100000000,r=0|8=8 +3、256 > 15 成立,shift = 4,v右移4位10000,r=8|4=12 +4、16 > 3 成立,shift = 2,右移2位100,r=12|2=14 +5、v=4,右移1位10,r|=2>>1=1 r=14|1=14 +*/ + +static __always_inline u64 log2(u32 v) { + u32 shift, r; + //检测v是否大于0xFFFF(65535),如果是,则将r设置为16 + r = (v > 0xFFFF) << 4; + v >>= r; //右移 + shift = (v > 0xFF) << 3; + v >>= shift; + r |= shift; + shift = (v > 0xF) << 2; + v >>= shift; + r |= shift; + shift = (v > 0x3) << 1; + v >>= shift; + r |= shift; + //右移v一位并将结果累加到r中 + r |= (v >> 1); + return r; +} +/* +例子:log2l(4294967296)=32 +4294967296 2进制表示 100000000000000000000000000000000 +1、v右移32位 1 +2、log2(1)=0 计算得0+32=32 +*/ +static __always_inline u64 log2l(u64 v) { + u32 hi = v >> 32; //取v的高32位 + // 如果高32位非0,计算高32位的对数并加32 + if (hi) + return log2(hi) + 32; + else + return log2(v); +} /* help functions end */ #endif diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index b7888b1c6..a2d059e90 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -106,9 +106,7 @@ int BPF_KPROBE(eth_type_trans, struct sk_buff *skb) { /** in only ipv4 */ SEC("kprobe/ip_rcv_core") // 跟踪记录ipv4数据包在内核中的处理时间 -int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { - return __ip_rcv_core(skb); -} +int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { return __ip_rcv_core(skb); } /** in only ipv6 */ SEC("kprobe/ip6_rcv_core") int BPF_KPROBE(ip6_rcv_core, struct sk_buff *skb) { @@ -117,15 +115,11 @@ int BPF_KPROBE(ip6_rcv_core, struct sk_buff *skb) { /**in only ipv4 */ // 接收数据包 SEC("kprobe/tcp_v4_rcv") // 记录数据包在tcpv4层时间戳 -int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { - return __tcp_v4_rcv(skb); -} +int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { return __tcp_v4_rcv(skb); } /** in only ipv6 */ SEC("kprobe/tcp_v6_rcv") // 接收tcpv6数据包 -int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { - return __tcp_v6_rcv(skb); -} +int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { return __tcp_v6_rcv(skb); } // v4 & v6 do_rcv to get sk and other info SEC("kprobe/tcp_v4_do_rcv") @@ -298,14 +292,10 @@ int BPF_KPROBE(ip_forward, struct sk_buff *skb) { // drop SEC("tp/skb/kfree_skb") -int tp_kfree(struct trace_event_raw_kfree_skb *ctx) { - return __tp_kfree(ctx); -} +int tp_kfree(struct trace_event_raw_kfree_skb *ctx) { return __tp_kfree(ctx); } SEC("kprobe/icmp_rcv") -int BPF_KPROBE(icmp_rcv, struct sk_buff *skb) { - return __icmp_time(skb); -} +int BPF_KPROBE(icmp_rcv, struct sk_buff *skb) { return __icmp_time(skb); } SEC("kprobe/__sock_queue_rcv_skb") int BPF_KPROBE(__sock_queue_rcv_skb, struct sock *sk, struct sk_buff *skb) { @@ -325,20 +315,17 @@ int handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { // mysql SEC("uprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") -int BPF_KPROBE(query__start) { - return __handle_mysql_start(ctx); -} +int BPF_KPROBE(query__start) { return __handle_mysql_start(ctx); } SEC("uretprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") -int BPF_KPROBE(query__end){ - return __handle_mysql_end(ctx); -} +int BPF_KPROBE(query__end) { return __handle_mysql_end(ctx); } SEC("uprobe/processCommand") -int BPF_KPROBE(query__start_redis_process) { - return __handle_redis_start(ctx); -} +int BPF_KPROBE(query__start_redis_process) { return __handle_redis_start(ctx); } SEC("uretprobe/call") -int BPF_KPROBE(query__end_redis){ - return __handle_redis_end(ctx); +int BPF_KPROBE(query__end_redis) { return __handle_redis_end(ctx); } +// rtt +SEC("kprobe/tcp_rcv_established") +int BPF_KPROBE(tcp_rcv_established, struct sock *sk, struct sk_buff *skb) { + return __tcp_rcv_established(sk, skb); } \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index 43e95dc2f..0d8a63088 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -44,7 +44,7 @@ static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, - redis_info = 0, count_info = 0; // flag + redis_info = 0, count_info = 0, rtt_info = 0; // flag static const char *tcp_states[] = { [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", @@ -67,7 +67,7 @@ static const struct argp_option opts[] = { {"udp", 'u', 0, 0, "trace the udp message"}, {"net_filter", 'n', 0, 0, "trace ipv4 packget filter "}, {"drop_reason", 'k', 0, 0, "trace kfree "}, - {"addr_to_func", 'T', 0, 0, "translation addr to func and offset"}, + {"addr_to_func", 'F', 0, 0, "translation addr to func and offset"}, {"icmptime", 'I', 0, 0, "set to trace layer time of icmp"}, {"tcpstate", 'S', 0, 0, "set to trace tcpstate"}, {"timeload", 'L', 0, 0, "analysis time load"}, @@ -82,6 +82,8 @@ static const struct argp_option opts[] = { {"redis", 'R', 0, 0}, {"count", 'C', "NUMBER", 0, "specify the time to count the number of requests"}, + {"rtt", 'T', 0, 0, "set to trace rtt"}, + {}}; static error_t parse_arg(int key, char *arg, struct argp_state *state) { @@ -120,7 +122,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'k': drop_reason = 1; break; - case 'T': + case 'F': addr_to_func = 1; break; case 'I': @@ -144,6 +146,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'R': redis_info = 1; break; + case 'T': + rtt_info = 1; + break; case 'C': count_info = strtoul(arg, &end, 10); break; @@ -173,6 +178,7 @@ enum MonitorMode { MODE_DNS, MODE_MYSQL, MODE_REDIS, + MODE_RTT, MODE_DEFAULT }; @@ -193,6 +199,8 @@ enum MonitorMode get_monitor_mode() { return MODE_MYSQL; } else if (redis_info) { return MODE_REDIS; + } else if (rtt_info) { + return MODE_RTT; } else { return MODE_DEFAULT; } @@ -426,77 +434,92 @@ static void set_rodata_flags(struct netwatcher_bpf *skel) { skel->rodata->stack_info = stack_info; skel->rodata->mysql_info = mysql_info; skel->rodata->redis_info = redis_info; + skel->rodata->rtt_info = rtt_info; } static void set_disable_load(struct netwatcher_bpf *skel) { bpf_program__set_autoload(skel->progs.inet_csk_accept_exit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v4_connect, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v4_connect_exit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v6_connect, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v6_connect_exit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_set_state, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.eth_type_trans, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.ip_rcv_core, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.ip6_rcv_core, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v4_rcv, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v6_rcv, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v4_do_rcv, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_v6_do_rcv, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.skb_copy_datagram_iter, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_validate_incoming, @@ -505,27 +528,32 @@ static void set_disable_load(struct netwatcher_bpf *skel) { err_packet ? true : false); bpf_program__set_autoload(skel->progs.tcp_sendmsg, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.ip_queue_xmit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.inet6_csk_xmit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.__dev_queue_xmit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.dev_hard_start_xmit, (all_conn || err_packet || extra_conn_info || - retrans_info || layer_time || http_info) + retrans_info || layer_time || http_info || + rtt_info) ? true : false); bpf_program__set_autoload(skel->progs.tcp_enter_recovery, @@ -567,6 +595,12 @@ static void set_disable_load(struct netwatcher_bpf *skel) { redis_info ? true : false); bpf_program__set_autoload(skel->progs.query__start_redis_process, redis_info ? true : false); + bpf_program__set_autoload(skel->progs.tcp_rcv_established, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); } static void print_header(enum MonitorMode mode) { @@ -636,6 +670,12 @@ static void print_header(enum MonitorMode mode) { printf("%-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", "Size", "Redis", "duration/μs"); break; + case MODE_RTT: + printf("===============================================================" + "====================RTT " + "INFORMATION====================================================" + "============================\n"); + break; case MODE_DEFAULT: printf("===============================================================" "=INFORMATION===================================================" @@ -784,7 +824,7 @@ static int print_conns(struct netwatcher_bpf *skel) { static int print_packet(void *ctx, void *packet_info, size_t size) { if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || - dns_info || mysql_info || redis_info) + dns_info || mysql_info || redis_info || rtt_info) return 0; const struct pack_t *pack_info = packet_info; if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || @@ -1179,6 +1219,59 @@ static int print_trace(void *_ctx, void *data, size_t size) { return 0; } +static int print_rtt(void *ctx, void *data, size_t size) { + if (!rtt_info) + return 0; + struct RTT *rtt_tuple = data; + unsigned long long total_latency = 0; + unsigned long long total_count = 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &rtt_tuple->saddr, s_str, sizeof(s_str)); + inet_ntop(AF_INET, &rtt_tuple->daddr, d_str, sizeof(d_str)); + if ((rtt_tuple->saddr & 0x0000FFFF) == 0x0000007F || + (rtt_tuple->daddr & 0x0000FFFF) == 0x0000007F || + rtt_tuple->saddr == htonl(0xC0A83C01) || + rtt_tuple->daddr == htonl(0xC0A83C01)) { + return 0; // 如果匹配任一过滤条件,放弃处理这些数据包 + } + // 打印源地址和目的地址 + printf("Source Address: %s\n", s_str); + printf("Destination Address: %s\n", d_str); + // 更新总延迟和计数 + total_latency += rtt_tuple->latency; + total_count += rtt_tuple->cnt; + + // 打印总延迟和平均RTT + double average_rtt = + (total_count > 0) ? (double)total_latency / total_count : 0; + printf("Total Latency: %llu μs\n", total_latency); + printf("Average RTT: %.2f ms\n", average_rtt / 1000.0); + + // 计算和打印RTT分布图 + printf(" usecs : count distribution\n"); + int bucket_size = 1; + for (int i = 0; i < MAX_SLOTS; i++) { + int start_range = bucket_size == 1 ? 0 : bucket_size; + int end_range = bucket_size * 2 - 1; + printf("%8d -> %-8d : %-8llu |", start_range, end_range, + rtt_tuple->slots[i]); + int bar_length = + rtt_tuple->slots[i] / + 10; //计算该延迟范围内的计数对应的直方图条形长度,每个'*' + //表示 10 个计数 + for (int j = 0; j < bar_length; j++) { + printf("*"); + } + printf("\n"); + bucket_size *= 2; //以对数方式扩展 + } + + printf("===============================================================\n"); + + return 0; +} + int attach_uprobe_mysql(struct netwatcher_bpf *skel) { ATTACH_UPROBE_CHECKED( @@ -1190,12 +1283,8 @@ int attach_uprobe_mysql(struct netwatcher_bpf *skel) { return 0; } int attach_uprobe_redis(struct netwatcher_bpf *skel) { - ATTACH_UPROBE_CHECKED( - skel, call, - query__end_redis); - ATTACH_UPROBE_CHECKED( - skel, processCommand, - query__start_redis_process); + ATTACH_UPROBE_CHECKED(skel, call, query__end_redis); + ATTACH_UPROBE_CHECKED(skel, processCommand, query__start_redis_process); return 0; } int main(int argc, char **argv) { @@ -1221,6 +1310,7 @@ int main(int argc, char **argv) { struct ring_buffer *trace_rb = NULL; struct ring_buffer *mysql_rb = NULL; struct ring_buffer *redis_rb = NULL; + struct ring_buffer *rtt_rb = NULL; struct netwatcher_bpf *skel; int err; /* Parse command line arguments */ @@ -1347,6 +1437,13 @@ int main(int argc, char **argv) { fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } + rtt_rb = + ring_buffer__new(bpf_map__fd(skel->maps.rtt_rb), print_rtt, NULL, NULL); + if (!rtt_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(connect_rb)\n"); + goto cleanup; + } /* Set up ring buffer polling */ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); if (!rb) { @@ -1369,6 +1466,7 @@ int main(int argc, char **argv) { err = ring_buffer__poll(trace_rb, 100 /* timeout, ms */); err = ring_buffer__poll(mysql_rb, 100 /* timeout, ms */); err = ring_buffer__poll(redis_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(rtt_rb, 100 /* timeout, ms */); print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h index 8687f3e13..a17775258 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h @@ -26,6 +26,7 @@ typedef unsigned long long u64; #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ +#define MAX_SLOTS 27 #ifndef AF_INET #define AF_INET 2 @@ -191,4 +192,12 @@ struct redis_query { u64 begin_time; int argc; }; + +struct RTT { + u32 saddr; + u32 daddr; + u64 slots[64]; + u64 latency; + u64 cnt; +}; #endif /* __NETWATCHER_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/tcp.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/tcp.bpf.h index adf0da84b..97eec262b 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/tcp.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/tcp.bpf.h @@ -17,9 +17,7 @@ #include "common.bpf.h" -static __always_inline -int __inet_csk_accept(struct sock *sk) -{ +static __always_inline int __inet_csk_accept(struct sock *sk) { if (sk == NULL) { // newsk is null // bpf_printk("inet_accept_ret err: newsk is null\n"); return 0; @@ -29,11 +27,11 @@ int __inet_csk_accept(struct sock *sk) CONN_INIT // 初始化conn_t结构中基本信息 conn.is_server = 1; - FILTER_DPORT // 过滤目标端口 + FILTER_DPORT // 过滤目标端口 - FILTER_SPORT // 过滤源端口 - - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + FILTER_SPORT // 过滤源端口 + + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 // 更新/插入conns_info中的键值对 int err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); @@ -45,9 +43,7 @@ int __inet_csk_accept(struct sock *sk) return 0; } -static __always_inline -int __tcp_v4_connect(const struct sock *sk) -{ +static __always_inline int __tcp_v4_connect(const struct sock *sk) { u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid int err = bpf_map_update_elem(&sock_stores, &ptid, &sk, BPF_ANY); // 更新/插入sock_stores中的键值对 @@ -58,9 +54,7 @@ int __tcp_v4_connect(const struct sock *sk) return 0; } -static __always_inline -int __tcp_v4_connect_exit(int ret) -{ +static __always_inline int __tcp_v4_connect_exit(int ret) { u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); // 获得sock_stores中ptid对应的*sk 用skp指向 @@ -75,13 +69,13 @@ int __tcp_v4_connect_exit(int ret) } struct sock *sk = *skp; CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 0; // 主动连接 + conn.is_server = 0; // 主动连接 - FILTER_DPORT // 过滤目标端口 + FILTER_DPORT // 过滤目标端口 - FILTER_SPORT // 过滤源端口 + FILTER_SPORT // 过滤源端口 - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); // 更新conns_info中sk对应的conn @@ -91,9 +85,7 @@ int __tcp_v4_connect_exit(int ret) return 0; } -static __always_inline -int __tcp_v6_connect(const struct sock *sk) -{ +static __always_inline int __tcp_v6_connect(const struct sock *sk) { u64 pid = bpf_get_current_pid_tgid(); // 获取pid int err = bpf_map_update_elem(&sock_stores, &pid, &sk, BPF_ANY); // 更新sock_stores中对应pid对应的sk @@ -103,9 +95,7 @@ int __tcp_v6_connect(const struct sock *sk) return 0; } -static __always_inline -int __tcp_v6_connect_exit(int ret) -{ +static __always_inline int __tcp_v6_connect_exit(int ret) { u64 ptid = bpf_get_current_pid_tgid(); // 获取pid struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); // 获得sock_stores中ptid对应的*sk 用skp指向 @@ -119,15 +109,15 @@ int __tcp_v6_connect_exit(int ret) struct sock *sk = *skp; CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 0; // 主动连接 + conn.is_server = 0; // 主动连接 - FILTER_DPORT // 过滤目标端口 + FILTER_DPORT // 过滤目标端口 - FILTER_SPORT // 过滤源端口 + FILTER_SPORT // 过滤源端口 - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 - long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); + long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); // 更新conns_info中sk对应的conn if (err) { return 0; @@ -135,9 +125,7 @@ int __tcp_v6_connect_exit(int ret) // bpf_printk("tcp_v4_connect_exit update sk: %p.\n", sk); return 0; } -static __always_inline -int __tcp_set_state( struct sock *sk, int state) -{ +static __always_inline int __tcp_set_state(struct sock *sk, int state) { if (all_conn) { return 0; } @@ -152,9 +140,8 @@ int __tcp_set_state( struct sock *sk, int state) } // receive error packet -static __always_inline -int __tcp_validate_incoming(struct sock *sk, struct sk_buff *skb) -{ +static __always_inline int __tcp_validate_incoming(struct sock *sk, + struct sk_buff *skb) { if (!err_packet) { return 0; } @@ -210,9 +197,7 @@ int __tcp_validate_incoming(struct sock *sk, struct sk_buff *skb) bpf_ringbuf_submit(packet, 0); return 0; } -static __always_inline -int skb_checksum_complete(int ret) -{ +static __always_inline int skb_checksum_complete(int ret) { if (!err_packet) { return 0; } @@ -243,9 +228,7 @@ int skb_checksum_complete(int ret) return 0; } ////retrans packet -static __always_inline -int __tcp_enter_recovery(struct sock *sk) -{ +static __always_inline int __tcp_enter_recovery(struct sock *sk) { if (!retrans_info) { return 0; } @@ -259,9 +242,7 @@ int __tcp_enter_recovery(struct sock *sk) return 0; } -static __always_inline -int __tcp_enter_loss(struct sock *sk) -{ +static __always_inline int __tcp_enter_loss(struct sock *sk) { if (!retrans_info) { return 0; } @@ -272,9 +253,8 @@ int __tcp_enter_loss(struct sock *sk) conn->timeout += 1; return 0; } -static __always_inline -int __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) -{ +static __always_inline int +__handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { if (ctx->protocol != IPPROTO_TCP) return 0; @@ -282,7 +262,7 @@ int __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) __u64 *before_time, new_time, time; before_time = bpf_map_lookup_elem(&tcp_state, &sk); - new_time= bpf_ktime_get_ns(); + new_time = bpf_ktime_get_ns(); if (!before_time) time = 0; else @@ -293,17 +273,19 @@ int __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) tcpstate.family = ctx->family; tcpstate.sport = ctx->sport; tcpstate.dport = ctx->dport; - bpf_probe_read_kernel(&tcpstate.saddr, sizeof(tcpstate.saddr), &sk->__sk_common.skc_rcv_saddr); - bpf_probe_read_kernel(&tcpstate.daddr, sizeof(tcpstate.daddr), &sk->__sk_common.skc_daddr); + bpf_probe_read_kernel(&tcpstate.saddr, sizeof(tcpstate.saddr), + &sk->__sk_common.skc_rcv_saddr); + bpf_probe_read_kernel(&tcpstate.daddr, sizeof(tcpstate.daddr), + &sk->__sk_common.skc_daddr); tcpstate.time = time; if (ctx->newstate == TCP_CLOSE) bpf_map_delete_elem(&tcp_state, &sk); else bpf_map_update_elem(&tcp_state, &sk, &new_time, BPF_ANY); - struct tcp_state *message; + struct tcp_state *message; message = bpf_ringbuf_reserve(&tcp_rb, sizeof(*message), 0); - if(!message){ + if (!message) { return 0; } message->saddr = tcpstate.saddr; @@ -312,7 +294,61 @@ int __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) message->dport = tcpstate.dport; message->oldstate = tcpstate.oldstate; message->newstate = tcpstate.newstate; - message->time = tcpstate.time; + message->time = tcpstate.time; + bpf_ringbuf_submit(message, 0); + return 0; +} + +static __always_inline int __tcp_rcv_established(struct sock *sk, + struct sk_buff *skb) { + const struct inet_sock *inet = (struct inet_sock *)(sk); + struct tcp_sock *ts; + struct hist *histp; + u64 slot; + u32 srtt; + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); + // INIT_PACKET_TCP_TUPLE(sk, pkt_tuple); + struct ip_packet key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr}; + + histp = bpf_map_lookup_elem(&hists, &key); + if (!histp) { + // 初始化值 + struct hist zero = {}; + bpf_map_update_elem(&hists, &key, &zero, BPF_ANY); + histp = bpf_map_lookup_elem(&hists, &key); + if (!histp) + return 0; // 如果仍然查找失败,则返回 + } + ts = (struct tcp_sock *)(sk); + + // 读取并处理SRTT(平滑往返时间) + srtt = BPF_CORE_READ(ts, srtt_us) >> 3; + // 计算对数值,根据得到的结果决定数据应该归入直方图的哪个槽位 + slot = log2l(srtt); + if (slot >= MAX_SLOTS) + slot = MAX_SLOTS - 1; // 确保槽位置不超过最大槽数 + + // 更新 + __sync_fetch_and_add(&histp->slots[slot], 1); + __sync_fetch_and_add(&histp->latency, srtt); + __sync_fetch_and_add(&histp->cnt, 1); + + struct RTT *message; + message = bpf_ringbuf_reserve(&rtt_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->saddr = pkt_tuple.saddr; + message->daddr = pkt_tuple.daddr; + bpf_printk("Saddr:%u Daddr:%u", pkt_tuple.saddr, pkt_tuple.daddr); + bpf_probe_read_kernel(message->slots, sizeof(message->slots), histp->slots); + message->latency = histp->latency; + message->cnt = histp->cnt; + // bpf_printk("Updating histogram: latency %llu, cnt %llu, slot %llu, + // slot_count %llu", histp->latency, histp->cnt, slot, histp->slots[slot]); bpf_ringbuf_submit(message, 0); return 0; } \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h index d39da361d..0b38ebb40 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h @@ -126,12 +126,7 @@ static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { u16 QR_flags; u64 *count_ptr, response_count = 0, request_count = 0; struct sock *sk = BPF_CORE_READ(skb, sk); - struct packet_tuple pkt_tuple = { - .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), - .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), - .sport = BPF_CORE_READ(sk, __sk_common.skc_num), - .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), - .tran_flag = UDP}; + INIT_PACKET_UDP_TUPLE(sk, pkt_tuple); // 使用saddr、daddr作为key struct dns key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr};