From 444eb438aefaf709c48876cd2caa90751f84bfe8 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 19 Oct 2022 17:07:15 +0800 Subject: [PATCH 01/13] common.mk: fix BTF not found error Signed-off-by: Menglong Dong --- common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.mk b/common.mk index d155cf3..96741bb 100644 --- a/common.mk +++ b/common.mk @@ -44,7 +44,7 @@ KERNEL_CFLAGS += $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ cmd_download = @if [ ! -f $(1) ]; then wget -O $(1) $(REMOTE_ROOT)/$(2); fi cmd_exist = $(if $(wildcard $(1)),$(2),$(3)) cmd_or_exist = $(call cmd_exist,$(1),$(1),$(2)) -ifeq ("$(wildcard $(HEADERS))$(wildcard $(BTF))",) +ifeq ("$(wildcard $(HEADERS))$(wildcard $(BTF))","") $(error BTF is not found in your system, please install kernel headers) endif -- Gitee From d1d28595676128241f2951fc8e9c8c5694b679b0 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 19 Oct 2022 19:14:08 +0800 Subject: [PATCH 02/13] ipv6 support of filtering and printing Add the new argument '--saddr_v6,--daddr_v6,--addr_v6' to support the ipv6. Signed-off-by: Menglong Dong --- component/arg_parse.c | 7 +++ component/arg_parse.h | 1 + component/net_utils.c | 39 ++++++++++++++++ component/net_utils.h | 9 ++-- shared/bpf/skb_shared.h | 6 +++ shared/bpf/skb_utils.h | 100 ++++++++++++++++++++++++++-------------- shared/common_args.h | 21 +++++++++ shared/pkt_utils.c | 11 +++-- 8 files changed, 153 insertions(+), 41 deletions(-) diff --git a/component/arg_parse.c b/component/arg_parse.c index 56882b6..a09d583 100644 --- a/component/arg_parse.c +++ b/component/arg_parse.c @@ -130,6 +130,13 @@ found: } S_SET(bool, true); break; + case OPTION_IPV6: + if (ipv6toi(optarg, item->dest)) { + printf("invalid ip address: %s\n", optarg); + goto err; + } + S_SET(bool, true); + break; case OPTION_HELP: goto help; case OPTION_PROTO: { diff --git a/component/arg_parse.h b/component/arg_parse.h index 8da144f..d829f81 100644 --- a/component/arg_parse.h +++ b/component/arg_parse.h @@ -15,6 +15,7 @@ enum option_type { OPTION_U32, OPTION_INT, OPTION_IPV4, + OPTION_IPV6, OPTION_HELP, OPTION_BLANK, OPTION_PROTO, diff --git a/component/net_utils.c b/component/net_utils.c index 125c9bd..e20013f 100644 --- a/component/net_utils.c +++ b/component/net_utils.c @@ -3,6 +3,9 @@ #include "net_utils.h" #include "arg_parse.h" +#define _LINUX_IN_H +#include + typedef struct { char *name; int val; @@ -143,3 +146,39 @@ int proto2i(char *proto, int *dest) return 4; return 0; } + +void i2ipv6(char *dest, __u8 ip[]) +{ + int i = 0, offset = 0; + + for (; i < 16; i += 2) { + if (ip[i] || ip[i + 1]) + offset += sprintf(dest + offset, "%02x%02x:", + ip[i], ip[i + 1]); + else + offset += sprintf(dest + offset, ":"); + } + *(dest + offset - 1) = '\0'; +} + +int ipv6toi(char *ip, __u8 *dest) +{ + u16 *c = (u16 *)dest; + u32 t[8] = {}, i = 0; + + if (sscanf(ip, "%x:%x:%x:%x:%x:%x:%x:%x", t, t + 1, t + 2, + t + 3, t + 4, t + 5, t + 6, t + 7) == 8) + goto is_valid; + + memset(t, 0, sizeof(t)); + if (sscanf(ip, "%x::%x:%x:%x:%x", t, t + 4, t + 5, t + 6, + t + 7) == 5) + goto is_valid; + + return -1; + +is_valid: + for (i = 0; i < 8; i++) + c[i] = htons(t[i]); + return 0; +} diff --git a/component/net_utils.h b/component/net_utils.h index f1dc4cc..15eeb5d 100644 --- a/component/net_utils.h +++ b/component/net_utils.h @@ -25,6 +25,8 @@ typedef __u32 u32; typedef __s64 s64; typedef __u64 u64; +extern char *l4_proto_names[]; + static inline void i2ip(char *dest, __u32 ip) { u8 *t = (u8 *)&ip; @@ -48,12 +50,13 @@ static inline int ip2i(char *ip, __u32 *dest) return 0; } -int proto2i(char *proto, int *dest); - -extern char *l4_proto_names[]; static inline char *i2l4(u8 num) { return l4_proto_names[num]; } +int proto2i(char *proto, int *dest); +void i2ipv6(char *dest, u8 ip[]); +int ipv6toi(char *ip, u8 *dest); + #endif \ No newline at end of file diff --git a/shared/bpf/skb_shared.h b/shared/bpf/skb_shared.h index d1120ee..bcb2d02 100644 --- a/shared/bpf/skb_shared.h +++ b/shared/bpf/skb_shared.h @@ -59,6 +59,12 @@ typedef struct { bool enable_daddr; u32 addr; bool enable_addr; + u8 saddr_v6[16]; + bool enable_saddr_v6; + u8 daddr_v6[16]; + bool enable_daddr_v6; + u8 addr_v6[16]; + bool enable_addr_v6; u16 sport; bool enable_sport; u16 dport; diff --git a/shared/bpf/skb_utils.h b/shared/bpf/skb_utils.h index 00f8e0c..ae7da55 100644 --- a/shared/bpf/skb_utils.h +++ b/shared/bpf/skb_utils.h @@ -26,11 +26,11 @@ struct { bpf_perf_event_output(ctx, &m_event, BPF_F_CURRENT_CPU, \ &(data), sizeof(data)) -#define _(P) \ -({ \ - typeof(P) tmp; \ - bpf_probe_read_kernel(&tmp, sizeof(P), &(P)); \ - tmp; \ +#define _(src) \ +({ \ + typeof(src) tmp; \ + bpf_probe_read_kernel(&tmp, sizeof(src), &(src)); \ + tmp; \ }) #ifdef MAP_CONFIG @@ -64,6 +64,8 @@ bpf_args_t _bpf_args; #define ARGS_GET_CONFIG(name) ((bpf_args_t *)CONFIG())->name #define ARGS_CHECK(name, val) \ (ARGS_ENABLED(name) && bpf_args->name != (val)) +#define ARGS_CHECK_OPS(name, value, ops) \ + (ARGS_ENABLED(name) && ops(bpf_args->name, value)) typedef struct { u64 pad; @@ -119,8 +121,9 @@ static try_inline u8 get_ip_header_len(u8 h) return len > IP_H_LEN ? len: IP_H_LEN; } -static try_inline void *load_l4_hdr(struct __sk_buff *skb, struct iphdr *ip, - void *dst, __u32 len) +static try_inline +void *load_l4_hdr(struct __sk_buff *skb, struct iphdr *ip, void *dst, + __u32 len) { __u32 offset, iplen; void *l4; @@ -147,10 +150,26 @@ static try_inline bool skb_l4_check(u16 l4, u16 l3) return l4 == 0xFFFF || l4 <= l3; } -#define CHECK_ATTR(attr) \ - ((ARGS_CHECK(attr, d##attr) && ARGS_CHECK(attr, s##attr)) || \ - ARGS_CHECK(s##attr, s##attr) || \ - ARGS_CHECK(d##attr, d##attr)) +static try_inline bool ipv6_not_equel(u8 *src, u8 *target) +{ + return *(u64 *)src != *(u64 *)target || + *(u64 *)(src + 8) != *(u64 *)(target + 8); +} + +#define ATTR_OPS(attr, ops) \ + ((ops(attr, d##attr) && ops(attr, s##attr)) || \ + ops(s##attr, s##attr) || \ + ops(d##attr, d##attr)) +#define ATTR_ENABLE_OPS(name, value) \ + ARGS_ENABLED(name) +#define ATTR_ENABLE(attr) \ + (filter && ATTR_OPS(attr, ATTR_ENABLE_OPS)) +#define ATTR_CHECK(attr) \ + (filter && ATTR_OPS(attr, ARGS_CHECK)) +#define ATTR_IPV6_OPS(attr, value) \ + ARGS_CHECK_OPS(attr##_v6, pkt->l3.ipv6.value, ipv6_not_equel) +#define ATTR_IPV6_CHECK() \ + (filter && ATTR_OPS(addr, ATTR_IPV6_OPS)) static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) { @@ -165,8 +184,9 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) if (pkt->proto_l3 == ETH_P_IPV6) { struct ipv6hdr *ipv6 = ip; - pkt->proto_l4 = _(ipv6->nexthdr); - l4 = l4 ?: ip + sizeof(*ipv6); + /* ipv4 address is set, skip ipv6 */ + if (ATTR_ENABLE(addr)) + goto err; bpf_probe_read_kernel(pkt->l3.ipv6.saddr, sizeof(ipv6->saddr), @@ -174,26 +194,34 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) bpf_probe_read_kernel(pkt->l3.ipv6.daddr, sizeof(ipv6->daddr), &ipv6->daddr); + + if (ATTR_IPV6_CHECK()) + goto err; + + pkt->proto_l4 = _(ipv6->nexthdr); + l4 = l4 ?: ip + sizeof(*ipv6); } else { struct iphdr *ipv4 = ip; - u32 saddr = _(ipv4->saddr); - u32 daddr = _(ipv4->daddr); + u32 saddr, daddr; - if (filter && CHECK_ATTR(addr)) - return -1; + /* skip ipv4 if ipv6 is set */ + if (ATTR_ENABLE(addr_v6)) + goto err; l4 = l4 ?: ip + get_ip_header_len(_(((u8 *)ip)[0])); + saddr = _(ipv4->saddr); + daddr = _(ipv4->daddr); + + if (ATTR_CHECK(addr)) + goto err; pkt->proto_l4 = _(ipv4->protocol); pkt->l3.ipv4.saddr = saddr; pkt->l3.ipv4.daddr = daddr; } - if (filter && ARGS_CHECK(l4_proto, pkt->proto_l4)) - return -1; - - bool port_filter = ARGS_ENABLED(sport) || ARGS_ENABLED(dport) || - ARGS_ENABLED(port); + if (ARGS_CHECK(l4_proto, pkt->proto_l4)) + goto err; switch (pkt->proto_l4) { case IPPROTO_TCP: { @@ -201,8 +229,8 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) u16 sport = _(tcp->source); u16 dport = _(tcp->dest); - if (filter && CHECK_ATTR(port)) - return -1; + if (ATTR_CHECK(port)) + goto err; pkt->l4.tcp.sport = sport; pkt->l4.tcp.dport = dport; @@ -216,8 +244,8 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) u16 sport = _(udp->source); u16 dport = _(udp->dest); - if (filter && CHECK_ATTR(port)) - return -1; + if (ATTR_CHECK(port)) + goto err; pkt->l4.udp.sport = sport; pkt->l4.udp.dport = dport; @@ -226,8 +254,8 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) case IPPROTO_ICMP: { struct icmphdr *icmp = l4; - if (filter && port_filter) - return -1; + if (ATTR_ENABLE(port)) + goto err; pkt->l4.icmp.code = _(icmp->code); pkt->l4.icmp.type = _(icmp->type); pkt->l4.icmp.seq = _(icmp->un.echo.sequence); @@ -235,10 +263,12 @@ static try_inline int probe_parse_ip(void *ip, parse_ctx_t *ctx) break; } default: - if (filter && port_filter) - return -1; + if (ATTR_ENABLE(port)) + goto err; } return 0; +err: + return -1; } static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) @@ -261,9 +291,9 @@ static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) */ l3_proto = bpf_ntohs(_(skb->protocol)); if (!l3_proto) - return -1; + goto err; if (!ctx->network_header) - return -1; + goto err; l3 = ctx->data + ctx->network_header; } else if (ctx->mac_header == ctx->network_header) { /* to tun device, mac header is the same to network header. @@ -280,7 +310,7 @@ static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) } if (filter && ARGS_CHECK(l3_proto, l3_proto)) - return -1; + goto err; ctx->trans_header = _(skb->transport_header); pkt->proto_l3 = l3_proto; @@ -291,9 +321,11 @@ static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) return probe_parse_ip(l3, ctx); default: if (filter && ARGS_ENABLED(l4_proto)) - return -1; + goto err; return 0; } +err: + return -1; } static try_inline int probe_parse_skb(struct sk_buff *skb, packet_t *pkt) diff --git a/shared/common_args.h b/shared/common_args.h index 3267edd..405308e 100644 --- a/shared/common_args.h +++ b/shared/common_args.h @@ -8,6 +8,13 @@ .set = &(args)->enable_saddr, \ .desc = "filter source ip address", \ }, \ + { \ + .lname = "saddr6", \ + .dest = &(args)->saddr_v6, \ + .type = OPTION_IPV6, \ + .set = &(args)->enable_saddr_v6, \ + .desc = "filter source ip v6 address", \ + }, \ { \ .lname = "daddr", \ .sname = 'd', \ @@ -16,6 +23,13 @@ .set = &(args)->enable_daddr, \ .desc = "filter dest ip address", \ }, \ + { \ + .lname = "daddr6", \ + .dest = &(args)->daddr_v6, \ + .type = OPTION_IPV6, \ + .set = &(args)->enable_daddr_v6, \ + .desc = "filter dest ip v6 address", \ + }, \ { \ .lname = "addr", \ .dest = &(args)->addr, \ @@ -23,6 +37,13 @@ .set = &(args)->enable_addr, \ .desc = "filter source or dest ip address", \ }, \ + { \ + .lname = "addr6", \ + .dest = &(args)->addr_v6, \ + .type = OPTION_IPV6, \ + .set = &(args)->enable_addr_v6, \ + .desc = "filter source or dest ip v6 address", \ + }, \ { \ .lname = "sport", \ .sname = 'S', \ diff --git a/shared/pkt_utils.c b/shared/pkt_utils.c index fda5290..6133486 100644 --- a/shared/pkt_utils.c +++ b/shared/pkt_utils.c @@ -6,7 +6,7 @@ int ts_print_packet(char *buf, packet_t *pkt, char *minfo) { - char saddr[MAX_ADDR_LENGTH], daddr[MAX_ADDR_LENGTH]; + static char saddr[MAX_ADDR_LENGTH], daddr[MAX_ADDR_LENGTH]; u8 flags, l4; int pos = 0; u64 ts; @@ -24,6 +24,12 @@ int ts_print_packet(char *buf, packet_t *pkt, char *minfo) switch (pkt->proto_l3) { case ETH_P_IP: + i2ip(saddr, pkt->l3.ipv4.saddr); + i2ip(daddr, pkt->l3.ipv4.daddr); + goto print_ip; + case ETH_P_IPV6: + i2ipv6(saddr, pkt->l3.ipv6.saddr); + i2ipv6(daddr, pkt->l3.ipv6.daddr); goto print_ip; case ETH_P_ARP: goto print_arp; @@ -35,9 +41,6 @@ int ts_print_packet(char *buf, packet_t *pkt, char *minfo) goto out; print_ip: - i2ip(saddr, pkt->l3.ipv4.saddr); - i2ip(daddr, pkt->l3.ipv4.daddr); - l4 = pkt->proto_l4; BUF_FMT("%s: ", i2l4(l4)); switch (l4) { -- Gitee From a534e3e739aecbd1b2cf87c4ef44e631f8b2e776 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 19 Oct 2022 20:02:20 +0800 Subject: [PATCH 03/13] add CO_RE support to skb for probe read Replace bpf_probe_read_kernel() with BPF_CORE_READ() when read the field of skb. Signed-off-by: Menglong Dong --- common.mk | 5 ++++- shared/bpf/skb_utils.h | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/common.mk b/common.mk index 96741bb..af9084e 100644 --- a/common.mk +++ b/common.mk @@ -120,7 +120,10 @@ progs/%.o: progs/%.c kheaders.h clang -O2 -c -g -S -Wall -Wno-pointer-sign -Wno-unused-value \ -Wno-incompatible-pointer-types-discards-qualifiers \ -fno-asynchronous-unwind-tables \ - $< -emit-llvm -Wno-unknown-attributes $(BPF_CFLAGS) -o - | \ + $< -emit-llvm -Wno-unknown-attributes $(BPF_CFLAGS) -Xclang \ + -disable-llvm-passes -o - | \ + opt -O2 -mtriple=bpf-pc-linux | \ + llvm-dis | \ llc -march=bpf -filetype=obj -o $@ @file $@ | grep debug_info > /dev/null || (rm $@ && exit 1) diff --git a/shared/bpf/skb_utils.h b/shared/bpf/skb_utils.h index ae7da55..89a45f9 100644 --- a/shared/bpf/skb_utils.h +++ b/shared/bpf/skb_utils.h @@ -5,6 +5,8 @@ * code. */ +#include + #include "macro.h" #include "skb_shared.h" @@ -32,6 +34,12 @@ struct { bpf_probe_read_kernel(&tmp, sizeof(src), &(src)); \ tmp; \ }) +#undef _C +#ifdef COMPAT_MODE +#define _C(src, a) _(src->a) +#else +#define _C(src, a, ...) BPF_CORE_READ(src, a, ##__VA_ARGS__) +#endif #ifdef MAP_CONFIG struct { @@ -280,16 +288,16 @@ static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) u16 l3_proto; void *l3; - ctx->network_header = _(skb->network_header); - ctx->mac_header = _(skb->mac_header); - ctx->data = _(skb->head); + ctx->network_header = _C(skb, network_header); + ctx->mac_header = _C(skb, mac_header); + ctx->data = _C(skb, head); if (skb_l2_check(ctx->mac_header)) { /* * try to parse skb for send path, which means that * ether header doesn't exist in skb. */ - l3_proto = bpf_ntohs(_(skb->protocol)); + l3_proto = bpf_ntohs(_C(skb, protocol)); if (!l3_proto) goto err; if (!ctx->network_header) @@ -312,7 +320,7 @@ static try_inline int probe_parse_skb_cond(parse_ctx_t *ctx) if (filter && ARGS_CHECK(l3_proto, l3_proto)) goto err; - ctx->trans_header = _(skb->transport_header); + ctx->trans_header = _C(skb, transport_header); pkt->proto_l3 = l3_proto; switch (l3_proto) { -- Gitee From 5b360f375f22e94e17794c4becb3eebd19ac5a9d Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 19 Oct 2022 21:12:50 +0800 Subject: [PATCH 04/13] remove unused field 'pskb' in struct trace 'pskb' is not needed anymore, we can remove it now. Signed-off-by: Menglong Dong --- legacy/nettrace.py | 6 +----- legacy/skb.yaml | 3 +-- src/trace.h | 1 - 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/legacy/nettrace.py b/legacy/nettrace.py index f5cefe2..46cf3df 100755 --- a/legacy/nettrace.py +++ b/legacy/nettrace.py @@ -50,7 +50,7 @@ class Tracer: def is_valid(tracer): if Tracer.is_tp(tracer): return True - if 'skb' not in tracer and 'pskb' not in tracer: + if 'skb' not in tracer: return False return True @@ -262,10 +262,6 @@ class Tracer: pad_index = tracer['skb'] skb_param = 'struct sk_buff *skb' bpf_prep = '' - elif 'pskb' in tracer: - pad_index = tracer['pskb'] - skb_param = 'struct sk_buff **pskb' - bpf_prep = 'struct sk_buff *skb = *pskb;' else: return diff --git a/legacy/skb.yaml b/legacy/skb.yaml index d3c8120..e42ab42 100644 --- a/legacy/skb.yaml +++ b/legacy/skb.yaml @@ -20,8 +20,7 @@ children: - name: __netif_receive_skb_core skb: 0 if: kernelVersion < 504 - - name: __netif_receive_skb_core - pskb: 0 + - name: __netif_receive_skb_core_pskb if: kernelVersion >= 504 - name: link-out desc: link layer (L2) of packet out diff --git a/src/trace.h b/src/trace.h index 0215f4b..f3fa739 100644 --- a/src/trace.h +++ b/src/trace.h @@ -44,7 +44,6 @@ typedef struct trace { char *regex; char *tp; int skb; - int pskb; struct list_head sibling; struct list_head list; struct list_head rules; -- Gitee From d131249798797658fadf81dd398a794a7e9aef30 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Thu, 20 Oct 2022 14:33:56 +0800 Subject: [PATCH 05/13] introduce compile argument COMPAT_MODE for low version kernel Rename 'MAP_CONFIG' with 'COMPAT_MODE' and use compatibility mode for 4.X kernel. Signed-off-by: Menglong Dong --- shared/bpf/skb_utils.h | 2 +- shared/bpf_utils.h | 2 +- src/Makefile | 2 +- src/gen_trace.py | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/shared/bpf/skb_utils.h b/shared/bpf/skb_utils.h index 89a45f9..ef9ed0c 100644 --- a/shared/bpf/skb_utils.h +++ b/shared/bpf/skb_utils.h @@ -41,7 +41,7 @@ struct { #define _C(src, a, ...) BPF_CORE_READ(src, a, ##__VA_ARGS__) #endif -#ifdef MAP_CONFIG +#ifdef COMPAT_MODE struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(key_size, sizeof(int)); diff --git a/shared/bpf_utils.h b/shared/bpf_utils.h index 5309a64..5cfcff9 100644 --- a/shared/bpf_utils.h +++ b/shared/bpf_utils.h @@ -18,7 +18,7 @@ typedef struct { extern long int syscall (long int __sysno, ...); -#ifdef MAP_CONFIG +#ifdef COMPAT_MODE #define bpf_set_config(skel, sec, value) do { \ int fd = bpf_map__fd(skel->maps.m_config); \ u8 buf[CONFIG_MAP_SIZE] = {}; \ diff --git a/src/Makefile b/src/Makefile index 823afa2..50e2ff8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ COMPAT ?= $(if $(KERNEL),$(shell cat $(HEADERS)/Makefile | grep \ 'VERSION = 4'),$(shell uname -r | grep ^4)) ifneq ($(strip $(COMPAT)),) - CFLAGS += -DMAP_CONFIG + CFLAGS += -DCOMPAT_MODE endif NFT_HEADER := $(HEADERS)/include/net/netfilter/nf_tables.h diff --git a/src/gen_trace.py b/src/gen_trace.py index d89ccc2..48b00ae 100755 --- a/src/gen_trace.py +++ b/src/gen_trace.py @@ -121,9 +121,10 @@ def gen_group(group, is_root=False): else: trace_type = 'TRACE_FUNCTION' if 'skb' in child: - skb_str = '\n\t.skb = {},'.format(child["skb"]) + skb_index = int(child["skb"]) + 1 + skb_str = '\n\t.skb = {},'.format(skb_index) probe_str += '\tFN({}, {})\t\\\n'.format(name, - int(child["skb"]) + 1) + skb_index) if 'analyzer' in child: analyzer = '\n\t.analyzer = &ANALYZER({}),'.format( child["analyzer"]) -- Gitee From a41d511fa31762a03f0e3994b13837a22497cde5 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Thu, 20 Oct 2022 20:03:46 +0800 Subject: [PATCH 06/13] rename 'intel' mode to 'diag' mode Signed-off-by: Menglong Dong --- README.md | 29 ++++++++++++++++------------- src/nettrace.c | 8 ++++---- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b4c781f..77750c8 100644 --- a/README.md +++ b/README.md @@ -139,8 +139,11 @@ nettrace: a tool to trace skb in kernel and diagnose network problem Usage: -s, --saddr filter source ip address + --saddr6 filter source ip v6 address -d, --daddr filter dest ip address + --daddr6 filter dest ip v6 address --addr filter source or dest ip address + --addr6 filter source or dest ip v6 address -S, --sport filter source TCP/UDP port -D, --dport filter dest TCP/UDP port -P, --port filter source or dest TCP/UDP port @@ -150,9 +153,9 @@ Usage: --ret show function return value --detail show extern packet info, such as pid, ifname, etc --basic use 'basic' trace mode, don't trace skb's life - --intel enable 'intel' mode - --intel-quiet only print abnormal packet - --intel-keep don't quit when abnormal packet found + --diag enable 'diagnose' mode + --diag-quiet only print abnormal packet + --diag-keep don't quit when abnormal packet found --hooks print netfilter hooks if dropping by netfilter -v show log information @@ -166,9 +169,9 @@ Usage: - `ret`:跟踪和显示内核函数的返回值 - `detail`:显示跟踪详细信息,包括当前的进程、网口和CPU等信息 - `basic`:启用`basic`跟踪模式。默认情况下,启用的是生命周期跟踪模式。启用该模式后,会直接打印出报文所经过的内核函数/tracepoint。 -- `intel`:启用诊断模式 -- `intel-quiet`:只显示出现存在问题的报文,不显示正常的报文 -- `intel-keep`:持续跟踪。`intel`模式是下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 +- `diag`:启用诊断模式 +- `diag-quiet`:只显示出现存在问题的报文,不显示正常的报文 +- `diag-keep`:持续跟踪。`diag`模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 - `hooks`:结合netfilter做的适配,详见下文 下面我们首先来看一下默认模式下的工具使用方法。 @@ -301,7 +304,7 @@ begin tracing...... ### 3.2 诊断模式 -使用方式与上面的一致,加个`intel`参数即可使用诊断模式。上文的生命周期模式对于使用者的要求比较高,需要了解内核协议栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在生命周期模式的基础上,提供了更加丰富的信息,使得没有网络开发经验的人也可进行复杂网络问题的定位和分析。 +使用方式与上面的一致,加个`diag`参数即可使用诊断模式。上文的生命周期模式对于使用者的要求比较高,需要了解内核协议栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在生命周期模式的基础上,提供了更加丰富的信息,使得没有网络开发经验的人也可进行复杂网络问题的定位和分析。 #### 3.2.1 基本用法 @@ -312,7 +315,7 @@ begin tracing...... - `ERROR`:异常信息,报文发生了问题(比如被丢弃)。 ```shell -./nettrace -p icmp --intel --saddr 192.168.122.8 +./nettrace -p icmp --diag --saddr 192.168.122.8 begin trace... ***************** ffff889fad356200 *************** [3445.575957] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 @@ -344,10 +347,10 @@ begin trace... NAT happens (packet address will change) ``` -如果当前报文存在`ERROR`,那么工具会给出一定的诊断修复建议,并终止当前诊断操作。通过添加`intel-keep`可以在发生`ERROR`事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: +如果当前报文存在`ERROR`,那么工具会给出一定的诊断修复建议,并终止当前诊断操作。通过添加`diag-keep`可以在发生`ERROR`事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: ```shell -./nettrace -p icmp --intel --saddr 192.168.122.8 +./nettrace -p icmp --diag --saddr 192.168.122.8 begin trace... ***************** ffff889fb3c64f00 *************** [4049.295546] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 @@ -397,7 +400,7 @@ end trace... 网络防火墙是网络故障、网络不同发生的重灾区,因此`netfilter`工具对`netfilter`提供了完美适配,包括老版本的`iptables-legacy`和新版本的`iptables-nft`。诊断模式下,`nettrace`能够跟踪报文所经过的`iptables`表和`iptables`链,并在发生由于iptables导致的丢包时给出一定的提示,上面的示例充分展现出了这部分。出了对iptables的支持,`nettrace`对整个netfilter大模块也提供了支持,能够显示在经过每个HOOK点时对应的协议族和链的名称。除此之外,为了应对一些注册到netfilter中的第三方内核模块导致的丢包问题,nettrace还可以通过添加参数`hooks`来打印出当前`HOOK`上所有的的钩子函数,从而深入分析问题: ```shell -./nettrace -p icmp --intel --saddr 192.168.122.8 --hooks +./nettrace -p icmp --diag --saddr 192.168.122.8 --hooks begin trace... ***************** ffff889faa054500 *************** [5810.702473] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 @@ -451,7 +454,7 @@ end trace... 端口未监听导致的丢包: ```shell -./nettrace --intel --intel-quiet +./nettrace --diag --diag-quiet begin trace... ***************** ffff888f97730ee0 *************** [365673.326016] [ip_output ] TCP: 127.0.0.1:40392 -> 127.0.0.1:9999 seq:3067626996, ack:0, flags:S @@ -485,7 +488,7 @@ begin trace... XDP导致的丢包(XDP转发会给提示): ```shell -./nettrace -p icmp --intel --intel-quiet +./nettrace -p icmp --diag --diag-quiet begin trace... ***************** ffff889f015acc00 *************** [18490.607809] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 diff --git a/src/nettrace.c b/src/nettrace.c index d6ce10d..aa8e7b4 100644 --- a/src/nettrace.c +++ b/src/nettrace.c @@ -49,17 +49,17 @@ static void do_parse_args(int argc, char *argv[]) .desc = "use 'basic' trace mode, don't trace skb's life", }, { - .lname = "intel", .dest = &trace_args->intel, + .lname = "diag", .dest = &trace_args->intel, .type = OPTION_BOOL, - .desc = "enable 'intel' mode", + .desc = "enable 'diagnose' mode", }, { - .lname = "intel-quiet", .dest = &trace_args->intel_quiet, + .lname = "diag-quiet", .dest = &trace_args->intel_quiet, .type = OPTION_BOOL, .desc = "only print abnormal packet", }, { - .lname = "intel-keep", .dest = &trace_args->intel_keep, + .lname = "diag-keep", .dest = &trace_args->intel_keep, .type = OPTION_BOOL, .desc = "don't quit when abnormal packet found", }, -- Gitee From d6d8da2c4559ef6d1f138f5fa6c533e80864566a Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Thu, 20 Oct 2022 20:06:12 +0800 Subject: [PATCH 07/13] 'drop' mode support for nettrace and remove droptrace Introduce the mode 'drop' for nettrace. Therefore, 'droptrace' is not needed anymore. With 'nettrace --drop', it performs the same as droptrace. Signed-off-by: Menglong Dong --- Makefile | 4 +- README.md | 28 +++- common.mk | 36 ----- component/sys_utils.c | 11 ++ component/sys_utils.h | 5 + droptrace/.gitignore | 5 - droptrace/Makefile | 31 ----- droptrace/README.md | 1 - droptrace/droptrace.c | 269 ------------------------------------- droptrace/progs/shared.h | 19 --- droptrace/reasons.h | 17 --- droptrace/vmlinux_header.h | 11 -- script/bash-completion.sh | 1 - script/nettrace.spec | 2 - script/zh_CN/nettrace.md | 20 +-- shared/pkt_utils.c | 2 +- src/.gitignore | 1 - src/Makefile | 4 +- src/analysis.c | 102 +++++++------- src/analysis.h | 4 +- src/dropreason.c | 55 ++++++++ src/dropreason.h | 7 + src/nettrace.c | 5 + src/progs/kprobe.c | 5 +- src/progs/shared.h | 6 + src/trace.c | 35 +++-- src/trace.h | 12 +- src/trace_probe.c | 1 + 28 files changed, 215 insertions(+), 484 deletions(-) delete mode 100644 droptrace/.gitignore delete mode 100644 droptrace/Makefile delete mode 120000 droptrace/README.md delete mode 100644 droptrace/droptrace.c delete mode 100644 droptrace/progs/shared.h delete mode 100644 droptrace/reasons.h delete mode 100644 droptrace/vmlinux_header.h create mode 100644 src/dropreason.c create mode 100644 src/dropreason.h diff --git a/Makefile b/Makefile index 7f41f73..3e9cb81 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ export VERSION = 1.2.1 RELEASE ?= .tl3 export RELEASE -targets := droptrace nodetrace src legacy +targets := nodetrace src legacy targets-call = for i in $1; do make $2 -C $$i $@; done man-target := script/zh_CN/nettrace.8 @@ -45,7 +45,7 @@ install: done @mkdir -p $(BCOMP); cd $(BCOMP); cp $(SCRIPT)/bash-completion.sh \ - ./nettrace; ln -s nettrace droptrace + ./nettrace pack: @make clean diff --git a/README.md b/README.md index 77750c8..f8897fc 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - 报文生命周期跟踪:跟踪网络报文从进入到内核协议栈到释放/丢弃的过程中在内核中所走过的路径,实现报文整个生命周期的监控,并采集生命周期各个阶段的事件、信息。通过观察报文在内核中的路径,对于有一定内核协议栈经验的人来说可以快速、有效地发现网络问题。 - 网络故障诊断:将以往的经验集成到工具的知识库,通过知识匹配的方式来主动诊断当前网络故障,给出诊断结果以及修复建议。该功能入手简单、易用性强,无需过多的网络经验即可进行网络问题定位。 - 网络异常监控:常态化地部署到生产环境中,主动地发现、上报环境上的网络异常。 -- `droptrace`:用于跟踪、监控系统中的丢包事件的工具,点击[这里](droptrace/README.md)查看详情介绍。该工具计划后面合入到`nettrace`功能中。 +- `droptrace`:用于跟踪、监控系统中的丢包事件的工具,点击[这里](docs/droptrace.md)查看详情介绍。该功能已被遗弃,可以使用`nettrace --drop`实现相同的功能。 ## 二、安装方法 @@ -131,7 +131,7 @@ make COMPAT=1 KERN_VER=266002 all ## 三、使用方法 -`droptrace`主要用来进行系统丢包事件的监控,点击[这里](droptrace/README.md)可查看droptrace的用户文档,这里不再赘述,重点介绍nettrace的相关功能。nettrace是用来跟踪内核报文和诊断网络故障的,在进行报文跟踪时可以使用一定的过滤条件来跟踪特定的报文。其基本命令行参数为: +nettrace是用来跟踪内核报文和诊断网络故障的,在进行报文跟踪时可以使用一定的过滤条件来跟踪特定的报文。其基本命令行参数为: ```shell $ nettrace -h @@ -157,6 +157,7 @@ Usage: --diag-quiet only print abnormal packet --diag-keep don't quit when abnormal packet found --hooks print netfilter hooks if dropping by netfilter + --drop skb drop monitor mode, for replace of 'droptrace' -v show log information --debug show debug information @@ -173,6 +174,7 @@ Usage: - `diag-quiet`:只显示出现存在问题的报文,不显示正常的报文 - `diag-keep`:持续跟踪。`diag`模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 - `hooks`:结合netfilter做的适配,详见下文 +- `drop`:进行系统丢包监控,取代原先的`droptrace` 下面我们首先来看一下默认模式下的工具使用方法。 @@ -513,3 +515,25 @@ begin trace... analysis finished! ``` + +## 3.3 丢包监控 + +使用命令`nettrace --drop`可以对系统中的丢包事件进行监控,对于支持内核特性`skb drop reason`的内核,这里还会打印出丢包原因。可以通过查看`/tracing/events/skb/kfree_skb/format`来判断当前系统是否支持该特性: + +```shell +cat /tracing/events/skb/kfree_skb/format +name: kfree_skb +ID: 1524 +format: + field:unsigned short common_type; offset:0; size:2; signed:0; + field:unsigned char common_flags; offset:2; size:1; signed:0; + field:unsigned char common_preempt_count; offset:3; size:1; signed:0; + field:int common_pid; offset:4; size:4; signed:1; + + field:void * skbaddr; offset:8; size:8; signed:0; + field:void * location; offset:16; size:8; signed:0; + field:unsigned short protocol; offset:24; size:2; signed:0; + field:enum skb_drop_reason reason; offset:28; size:4; signed:0; + +print fmt: "skbaddr=%p protocol=%u location=%p reason: %s", REC->skbaddr, REC->protocol, REC->location, __print_symbolic(REC->reason, { 1, "NOT_SPECIFIED" }, { 2, "NO_SOCKET" }, { 3, "PKT_TOO_SMALL" }, { 4, "TCP_CSUM" }, { 5, "SOCKET_FILTER" }, { 6, "UDP_CSUM" }, { 7, "NETFILTER_DROP" }, { 8, "OTHERHOST" }, { 9, "IP_CSUM" }, { 10, "IP_INHDR" }, { 11, "IP_RPFILTER" }, { 12, "UNICAST_IN_L2_MULTICAST" }, { 13, "XFRM_POLICY" }, { 14, "IP_NOPROTO" }, { 15, "SOCKET_RCVBUFF" }, { 16, "PROTO_MEM" }, { 17, "TCP_MD5NOTFOUND" }, { 18, "TCP_MD5UNEXPECTED" }, { 19, "TCP_MD5FAILURE" }, { 20, "SOCKET_BACKLOG" }, { 21, "TCP_FLAGS" }, { 22, "TCP_ZEROWINDOW" }, { 23, "TCP_OLD_DATA" }, { 24, "TCP_OVERWINDOW" }, { 25, "TCP_OFOMERGE" }, { 26, "TCP_RFC7323_PAWS" }, { 27, "TCP_INVALID_SEQUENCE" }, { 28, "TCP_RESET" }, { 29, "TCP_INVALID_SYN" }, { 30, "TCP_CLOSE" }, { 31, "TCP_FASTOPEN" }, { 32, "TCP_OLD_ACK" }, { 33, "TCP_TOO_OLD_ACK" }, { 34, "TCP_ACK_UNSENT_DATA" }, { 35, "TCP_OFO_QUEUE_PRUNE" }, { 36, "TCP_OFO_DROP" }, { 37, "IP_OUTNOROUTES" }, { 38, "BPF_CGROUP_EGRESS" }, { 39, "IPV6DISABLED" }, { 40, "NEIGH_CREATEFAIL" }, { 41, "NEIGH_FAILED" }, { 42, "NEIGH_QUEUEFULL" }, { 43, "NEIGH_DEAD" }, { 44, "TC_EGRESS" }, { 45, "QDISC_DROP" }, { 46, "CPU_BACKLOG" }, { 47, "XDP" }, { 48, "TC_INGRESS" }, { 49, "UNHANDLED_PROTO" }, { 50, "SKB_CSUM" }, { 51, "SKB_GSO_SEG" }, { 52, "SKB_UCOPY_FAULT" }, { 53, "DEV_HDR" }, { 54, "DEV_READY" }, { 55, "FULL_RING" }, { 56, "NOMEM" }, { 57, "HDR_TRUNC" }, { 58, "TAP_FILTER" }, { 59, "TAP_TXFILTER" }, { 60, "ICMP_CSUM" }, { 61, "INVALID_PROTO" }, { 62, "IP_INADDRERRORS" }, { 63, "IP_INNOROUTES" }, { 64, "PKT_TOO_BIG" }, { 65, "MAX" }) +``` diff --git a/common.mk b/common.mk index af9084e..9c3be08 100644 --- a/common.mk +++ b/common.mk @@ -56,24 +56,12 @@ ifeq ($(if $(VMLINUX),$(wildcard $(VMLINUX)),"pass"),) $(error vmlinux path not exist) endif -# preferred to generate drop reason from -ifeq ("$(KERNEL)$(VMLINUX)","") - DROP_REASON := $(call cmd_or_exist,$(HEADERS)/include/net/dropreason.h,\ - $(call cmd_or_exist,$(HEADERS)/include/linux/skbuff.h,\ - $(call cmd_exist,$(BTF),vmlinux.h,))) -endif - # preferred to compile from kernel headers, then BTF mode := $(if $(VMLINUX),'btf',$(call cmd_exist,$(HEADERS),'kernel','btf')) ifeq ($(mode),'btf') - DROP_REASON ?= vmlinux.h kheaders_cmd := ln -s vmlinux.h kheaders.h kheaders_dep := vmlinux.h else -ifndef DROP_REASON - DROP_REASON := $(call cmd_or_exist,$(HEADERS)/include/net/dropreason.h,\ - $(call cmd_or_exist,$(HEADERS)/include/linux/skbuff.h,)) -endif kheaders_cmd := ln -s vmlinux_header.h kheaders.h BPF_CFLAGS += $(KERNEL_CFLAGS) endif @@ -92,30 +80,6 @@ vmlinux.h: kheaders.h: $(kheaders_dep) $(call kheaders_cmd) -drop_reason.h: $(DROP_REASON) - rm -rf $@ -ifneq ($(strip $(DROP_REASON)),) - @awk 'BEGIN{ print "#ifndef _H_SKB_DROP_REASON"; \ - print "#define _H_SKB_DROP_REASON\n";\ - system("sed -e \"/enum skb_drop_reason {/,/}/!d\" $< >> $@");\ - print "\n#define __DEFINE_SKB_REASON(FN) \\";\ - }\ - /^enum skb_drop/ { dr=1; }\ - /^\};/ { dr=0; }\ - /^\tSKB_DROP_REASON_/ {\ - if (dr) {\ - sub(/SKB_DROP_REASON_/, "", $$1);\ - sub(/,/, "", $$1);\ - printf "\tFN(%s)\t\\\n", $$1;\ - }\ - }\ - END{ print "\n#endif" }' $< >> $@ - @echo generated drop_reason.h -else - touch $@ - @echo drop reason not supported, skips -endif - progs/%.o: progs/%.c kheaders.h clang -O2 -c -g -S -Wall -Wno-pointer-sign -Wno-unused-value \ -Wno-incompatible-pointer-types-discards-qualifiers \ diff --git a/component/sys_utils.c b/component/sys_utils.c index 4d5bb07..be56688 100644 --- a/component/sys_utils.c +++ b/component/sys_utils.c @@ -57,3 +57,14 @@ int liberate_l() struct rlimit lim = {RLIM_INFINITY, RLIM_INFINITY}; return setrlimit(RLIMIT_MEMLOCK, &lim); } + +bool fsearch(FILE *f, char *target) +{ + char tmp[128]; + + while (fscanf(f, "%s", tmp) == 1) { + if (strstr(tmp, target)) + return true; + } + return false; +} diff --git a/component/sys_utils.h b/component/sys_utils.h index c677092..111547a 100644 --- a/component/sys_utils.h +++ b/component/sys_utils.h @@ -6,12 +6,17 @@ #include #include #include +#include +#include +#include +#include extern int log_level; int execf(char *output, char *fmt, ...); int exec(char *cmd, char *output); int liberate_l(); +bool fsearch(FILE *f, char *target); static inline int simple_exec(char *cmd) { diff --git a/droptrace/.gitignore b/droptrace/.gitignore deleted file mode 100644 index 44a0d8f..0000000 --- a/droptrace/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -drop_reason.h -droptrace -progs/common.h -progs/probe.c -progs/trace.c diff --git a/droptrace/Makefile b/droptrace/Makefile deleted file mode 100644 index ef0689d..0000000 --- a/droptrace/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -ROOT ?= $(abspath ../) -bpf_progs = progs/probe progs/trace -progs = droptrace -prog-droptrace = droptrace.c $(COMMON_SHARED) drop_reason.h \ - $(COMPONENT)/parse_sym.c - -include ../common.mk - -progs/common.h: - $(call cmd_download,$@,droptrace/$@) - -$(foreach i,$(bpf_progs),$(i).c): progs/common.h drop_reason.h - $(call cmd_download,$@,droptrace/$@) - -droptrace.c: drop_reason.h - @if [ -z `grep SKB_DROP_REASON_MAX drop_reason.h` ];then \ - echo 'drop reason is not supported by current kernel'; \ - exit -1; \ - fi - -all: $(progs) - -install: all - @mkdir -p $(PREFIX)/usr/bin/ && cp droptrace $(PREFIX)/usr/bin/ - -pack: all - @mkdir -p $(PREFIX) && cp droptrace $(PREFIX) - -clean: - rm -rf drop_reason.h droptrace vmlinux.h progs/*.skel.h \ - progs/*.o kheaders.h diff --git a/droptrace/README.md b/droptrace/README.md deleted file mode 120000 index 0153b17..0000000 --- a/droptrace/README.md +++ /dev/null @@ -1 +0,0 @@ -../docs/droptrace.md \ No newline at end of file diff --git a/droptrace/droptrace.c b/droptrace/droptrace.c deleted file mode 100644 index aee896d..0000000 --- a/droptrace/droptrace.c +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: MulanPSL-2.0 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "reasons.h" -#include "./progs/shared.h" -#include - -#include "progs/probe.skel.h" -#include "progs/trace.skel.h" - -#define MAX_OUTPUT_LENGTH 256 -#define ROOT_PIN_PATH "/sys/fs/bpf/droptrace/" -#define SNMP_PIN_PATH ROOT_PIN_PATH"snmp" -#define TRACE_PIN_PATH ROOT_PIN_PATH"trace" - -u32 snmp_reasons[SKB_DROP_REASON_MAX]; - -static bool snmp_mode = false, - ts_show = false, - raw_sym = false; -static char buf[1024]; -static arg_config_t prog_config = { - .name = "droptrace", - .summary = "a tool to monitor the packet dropped by kernel", - .desc = "" -}; - -static void print_drop_packet(void *ctx, int cpu, void *data, __u32 size) -{ - char ts_str[32], raw_sym_desc[20]; - const char *reason_str; - struct sym_result *sym; - char *sym_desc = NULL; - event_t *e = data; - u16 reason; - - reason = e->reason; - if (reason >= SKB_DROP_REASON_MAX || reason <= 0) { - printf("unknow drop reason: %d", reason); - reason = SKB_DROP_REASON_NOT_SPECIFIED; - } - reason_str = drop_reasons[reason]; - if (!reason_str) - printf("invalid reason found:%d\n", reason); - if (!raw_sym) { - sym = parse_sym(e->location); - sym_desc = sym->desc; - } else { - sym_desc = raw_sym_desc; - sprintf(sym_desc, "0x%llx", e->location); - } - - base_print_packet(buf, &e->pkt); - printf("%s reason:%s %s\n", buf, reason_str, sym_desc); -} - -static void print_drop_stat(int fd) -{ - int key = 0, i = 1, count; - - if (bpf_map_lookup_elem(fd, &key, snmp_reasons)) { - printf("failed to load data\n"); - return; - } - - printf("packet statistics:\n"); - for (; i < SKB_DROP_REASON_MAX; i++) { - count = snmp_reasons[i]; - printf(" %s: %d\n", drop_reasons[i], count); - } -} - -static int do_stat_stop() -{ - if (access(SNMP_PIN_PATH, F_OK)) { - printf("not loaded\n"); - goto err; - } - unlink(TRACE_PIN_PATH); - unlink(SNMP_PIN_PATH); - printf("stat stop successful!\n"); - return 0; - -err: - return -1; -} - -static int parse_opts(int argc, char *argv[], bpf_args_t *args) -{ - bool stat_stop = false; - int proto_l = 0; - u16 proto; - - option_item_t opts[] = { - COMMON_PROG_ARGS(&args->pkt), - { - .lname = "reason", - .sname = 'r', - .dest = &args->reason, - .type = OPTION_U16, - .set = &args->enable_reason, - .desc = "filter drop reason", - }, - { .type = OPTION_BLANK }, - { - .lname = "raw-sym", - .dest = &raw_sym, - .type = OPTION_BOOL, - .desc = "show kernel symbol address (default false)" - }, - { - .lname = "stat", - .dest = &snmp_mode, - .type = OPTION_BOOL, - .desc = "show drop statistics", - }, - { - .lname = "stat-stop", - .dest = &stat_stop, - .type = OPTION_BOOL, - .desc = "stop drop statistics and remove the launched" - " eBPF program", - }, - { - .lname = "limit", - .sname = 'l', - .dest = &args->limit, - .type = OPTION_U32, - .set = &args->enable_limit, - .desc = "set the max output pcaket per second, default" - "unlimited", - }, - { - .lname = "limit-budget", - .dest = &args->limit_bucket, - .type = OPTION_U32, - .set = &args->enable_limit_bucket, - .desc = "set the budget depth of the token used to limit" - "output rate", - }, - { - .lname = "help", - .sname = 'h', - .type = OPTION_HELP, - .desc = "show help information", - }, - }; - - if (parse_args(argc, argv, &prog_config, opts, ARRAY_SIZE(opts))) - goto err; - - if (proto_l == 3) { - args->pkt.enable_l3_proto = true; - args->pkt.l3_proto = proto; - } else if (proto_l == 4) { - args->pkt.enable_l4_proto = true; - args->pkt.l4_proto = proto; - } - - if (stat_stop) { - do_stat_stop(); - goto exit; - } - - args->snmp_mode = snmp_mode; - return 0; -err: - return -1; -exit: - exit(0); -} - -#define SKEL_OPS(ops, ...) ({ \ - trace ? trace__##ops (__VA_ARGS__) : \ - probe__##ops (__VA_ARGS__); \ - }) -#define SKEL_OBJ_FD(type, name) \ - bpf_##type##__fd(trace ? trace->type##s.name : \ - probe->type##s.name) - -int main(int argc, char *argv[]) -{ - bpf_args_t bpf_args = {}; - struct trace *trace; - struct probe *probe; - int map_fd; - void *obj; - - if (parse_opts(argc, argv, &bpf_args)) - goto err; - if (snmp_mode) - goto do_snmp; - -do_load: - libbpf_set_print(NULL); - trace = trace__open(); - probe = probe__open(); - bpf_set_config(probe, data, bpf_args); - bpf_set_config(trace, data, bpf_args); - liberate_l(); - - if (trace__load(trace)) { - trace__destroy(trace); - trace = NULL; - if (probe__load(probe)) { - printf("failed to load program\n"); - goto err; - } - } - obj = (void *)trace ?: (void *)probe; - - if (SKEL_OPS(attach, obj)) { - printf("failed to attach kfree_skb\n"); - goto err; - } - - if (snmp_mode) - goto do_snmp_pin; - - perf_output(SKEL_OBJ_FD(map, m_event), print_drop_packet); - SKEL_OPS(destroy, obj); - return 0; - -err: - SKEL_OPS(destroy, obj); - return -1; - -do_snmp_pin: - if (access(ROOT_PIN_PATH, F_OK) && mkdir(ROOT_PIN_PATH, 744)) { - printf("failed to create bpf pin path\n"); - goto err; - } - if (bpf_obj_pin(SKEL_OBJ_FD(map, data), SNMP_PIN_PATH)) { - printf("failed to pin snmp map\n"); - goto err; - } - if (bpf_obj_pin(SKEL_OBJ_FD(link, trace_kfree_skb), - TRACE_PIN_PATH)) { - printf("failed to pin program (your kernel seems don't " - "support bpf_link)\n"); - unlink(SNMP_PIN_PATH); - goto err; - } - trace__destroy(obj); - -do_snmp: - if (access(SNMP_PIN_PATH, F_OK)) - goto do_load; - map_fd = bpf_obj_get(SNMP_PIN_PATH); - if (map_fd < 0) { - printf("failed to open snmp\n"); - return -1; - } - print_drop_stat(map_fd); - return 0; -} diff --git a/droptrace/progs/shared.h b/droptrace/progs/shared.h deleted file mode 100644 index d31f6e8..0000000 --- a/droptrace/progs/shared.h +++ /dev/null @@ -1,19 +0,0 @@ -#include - -typedef struct { - u64 location; - packet_t pkt; - u16 reason; -} event_t; - -#define DEFINE_BPF_ARGS() \ - u16 reason; \ - bool enable_reason; \ - u32 limit; \ - bool enable_limit; \ - u32 limit_bucket; \ - bool enable_limit_bucket; \ - bool snmp_mode; \ - u32 snmp_reasons[SKB_DROP_REASON_MAX]; \ - int current_budget; \ - u64 last_ts diff --git a/droptrace/reasons.h b/droptrace/reasons.h deleted file mode 100644 index cf42ffa..0000000 --- a/droptrace/reasons.h +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MulanPSL-2.0 - -#ifndef _H_TRACE_REASONS -#define _H_TRACE_REASONS - -#include - -/* drop_reasons is used to translate 'enum skb_drop_reason' to string, - * which is reported to user space. - */ -static const char * const drop_reasons[] = { -#define FN(name) [SKB_DROP_REASON_##name] = #name, - __DEFINE_SKB_REASON(FN) -#undef FN -}; - -#endif \ No newline at end of file diff --git a/droptrace/vmlinux_header.h b/droptrace/vmlinux_header.h deleted file mode 100644 index d6232c5..0000000 --- a/droptrace/vmlinux_header.h +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MulanPSL-2.0 - -#define KBUILD_MODNAME "" -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/script/bash-completion.sh b/script/bash-completion.sh index c3f80d5..5080186 100644 --- a/script/bash-completion.sh +++ b/script/bash-completion.sh @@ -1,3 +1,2 @@ complete -W '-s --saddr -d --daddr --addr -p -D --dport -S --sport -P --port -t --trace -v --detail --debug --ret --basic --intel --intel-quiet --intel-keep --hooks -h --help' nettrace complete -W '-h -s -d --addr -p --dport --sport --port -t -v --detail --stack --stack-tracer --timeline -c --ret --skb-mode --force-stack --tcp-flags -o --output' nettrace-legacy -complete -W '-s --saddr -d --daddr --addr -S --sport -D --dport -P --port -p --proto -r --reason --raw-sym --stat --stat-stop -l --limit --limit-budget -h --help' droptrace \ No newline at end of file diff --git a/script/nettrace.spec b/script/nettrace.spec index 535c05b..e714ab9 100644 --- a/script/nettrace.spec +++ b/script/nettrace.spec @@ -41,7 +41,6 @@ PREFIX=$RPM_BUILD_ROOT /opt/nettrace/ /usr/bin/nettrace /usr/bin/nettrace-legacy -%ghost /usr/bin/droptrace /usr/bin/nodetrace-mark /usr/bin/nodetrace-watch /usr/share/man/man8/nettrace-legacy.8.gz @@ -49,7 +48,6 @@ PREFIX=$RPM_BUILD_ROOT /usr/share/man/man8/nettrace.8.gz /usr/share/man/man8/dropreason.8.gz /usr/share/bash-completion/completions/nettrace -/usr/share/bash-completion/completions/droptrace %doc diff --git a/script/zh_CN/nettrace.md b/script/zh_CN/nettrace.md index 4dc51c4..77bf5d2 100644 --- a/script/zh_CN/nettrace.md +++ b/script/zh_CN/nettrace.md @@ -60,14 +60,14 @@ nettrace - Linux系统下的网络报文跟踪、网络问题诊断工具 启用`basic`跟踪模式。默认情况下,启用的是生命周期跟踪模式。启用该模式后,会直接打印 出报文所经过的内核函数/tracepoint -`--intel` +`--diag` 启用诊断模式 -`--intel-quiet` +`--diag-quiet` 只显示出现存在问题的报文,不显示正常的报文 -`--intel-keep` - 持续跟踪。`intel`模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 +`--diag-keep` + 持续跟踪。`diag`模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 `--hooks` 打印netfilter上的钩子函数 @@ -93,7 +93,7 @@ nettrace - Linux系统下的网络报文跟踪、网络问题诊断工具 ### 诊断模式 -使用方式与上面的一致,加个`intel`参数即可使用诊断模式。上文的生命周期模式对于使用者的 +使用方式与上面的一致,加个`diag`参数即可使用诊断模式。上文的生命周期模式对于使用者的 要求比较高,需要了解内核协议栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在 生命周期模式的基础上,提供了更加丰富的信息,使得没有网络开发经验的人也可进行复杂 网络问题的定位和分析。 @@ -106,10 +106,10 @@ nettrace - Linux系统下的网络报文跟踪、网络问题诊断工具 - `ERROR`:异常信息,报文发生了问题(比如被丢弃)。 如果当前报文存在`ERROR`,那么工具会给出一定的诊断修复建议,并终止当前诊断操作。通过添 -加`intel-keep`可以在发生`ERROR`事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: +加`diag-keep`可以在发生`ERROR`事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: ```shell -./nettrace -p icmp --intel --saddr 192.168.122.8 +./nettrace -p icmp --diag --saddr 192.168.122.8 begin trace... ***************** ffff889fb3c64f00 *************** [4049.295546] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 0 @@ -158,7 +158,7 @@ end trace... 适配的,可以理解为将droptrace的功能集成到了这里的诊断结果中,这里可以看出其给出的丢包 原因是`NETFILTER_DROP`。因此,可以通过一下命令来监控内核中所有的丢包事件以及丢包原因: -*nettrace -t kfree_skb --intel --intel-keep* +*nettrace -t kfree_skb --diag --diag-keep* ### netfilter支持 @@ -172,7 +172,7 @@ end trace... 分析问题: ```shell -./nettrace -p icmp --intel --saddr 192.168.122.8 --hooks +./nettrace -p icmp --diag --saddr 192.168.122.8 --hooks begin trace... ***************** ffff889faa054500 *************** [5810.702473] [__netif_receive_skb_core] ICMP: 192.168.122.8 -> 10.123.119.98 ping request, seq: 943 @@ -234,4 +234,4 @@ Menglong Dong ## SEE ALSO -nettrace-legacy(8), droptrace(8) +nettrace-legacy(8) diff --git a/shared/pkt_utils.c b/shared/pkt_utils.c index 6133486..c7f31ee 100644 --- a/shared/pkt_utils.c +++ b/shared/pkt_utils.c @@ -16,7 +16,7 @@ int ts_print_packet(char *buf, packet_t *pkt, char *minfo) BUF_FMT("[%llu.%06llu] ", ts / 1000000000, ts % 1000000000 / 1000); if (minfo) - BUF_FMT("%s ", minfo); + BUF_FMT("%s", minfo); if (!pkt->proto_l3) { BUF_FMT("unknow"); goto out; diff --git a/src/.gitignore b/src/.gitignore index 1d3209f..8b9830c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,3 @@ trace_group.c kprobe_trace.h nettrace -drop_reason.h diff --git a/src/Makefile b/src/Makefile index 50e2ff8..89d84b7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ progs := nettrace prog-nettrace-origin = \ trace.c $(COMMON_SHARED) trace_probe.c trace_tracing.c \ analysis.c $(COMPONENT)/parse_sym.c trace_group.c \ - drop_reason.h + dropreason.c prog-nettrace = $(prog-nettrace-origin) nettrace.c ifdef KERN_VER @@ -48,5 +48,5 @@ pack: all clean: rm -rf $(progs) trace_group.c progs/kprobe_trace.h \ $(bpf_progs) progs/*.o progs/*.skel.h \ - vmlinux.h drop_reason.h kheaders.h + vmlinux.h kheaders.h diff --git a/src/analysis.c b/src/analysis.c index 6719837..7f4dc77 100644 --- a/src/analysis.c +++ b/src/analysis.c @@ -12,7 +12,7 @@ #include "trace.h" #include "analysis.h" -#include "drop_reason.h" +#include "dropreason.h" #define CTX_HASH_LENGTH 1024 static struct hlist_head ctx_hash[CTX_HASH_LENGTH] = {}; @@ -157,11 +157,11 @@ static void analy_entry_handle(analy_entry_t *entry) ifname = ifname ?: ""; } - sprintf(tinfo, "[%llx][%-20s][cpu:%-3u][%-5s][pid:%-7u][%-12s]", + sprintf(tinfo, "[%llx][%-20s][cpu:%-3u][%-5s][pid:%-7u][%-12s] ", detail->key, t->name, entry->cpu, ifname, detail->pid, detail->task); - } else { - sprintf(tinfo, "[%-20s]", t->name); + } else if (trace_ctx.mode != TRACE_MODE_DROP) { + sprintf(tinfo, "[%-20s] ", t->name); } ts_print_packet(buf, pkt, tinfo); @@ -174,7 +174,7 @@ static void analy_entry_handle(analy_entry_t *entry) (int)entry->priv); if (entry->msg) - sprintf_end(buf, PFMT_EMPH_STR(" *%s*"), entry->msg); + sprintf_end(buf, "%s", entry->msg); if (!entry->rule) goto out; @@ -278,6 +278,16 @@ free_ctx: analy_ctx_free(ctx); } +static int try_run_analyzer(trace_t *trace, analyzer_t *analyzer, + analy_entry_t *entry) +{ + if (analyzer && (analyzer->mode & (1 << trace_ctx.mode)) && + analyzer->analy_entry) + return analyzer->analy_entry(trace, entry); + + return RESULT_CONT; +} + void tl_poll_handler(void *raw_ctx, int cpu, void *data, u32 size) { static char buf[1024], tinfo[128]; @@ -318,28 +328,22 @@ void tl_poll_handler(void *raw_ctx, int cpu, void *data, u32 size) entry->ctx = analy_ctx; entry->fake_ctx = fake; - if (analyzer->analy_entry) { - switch (analyzer->analy_entry(trace, entry)) { - case RESULT_CONSUME: - goto check_pending; - case RESULT_CONT: - break; - default: - break; - } + switch (try_run_analyzer(trace, analyzer, entry)) { + case RESULT_CONSUME: + goto check_pending; + case RESULT_CONT: + break; + default: + break; } - analyzer = trace->analyzer; - if (analyzer && (analyzer->mode & (1 << trace_ctx.mode)) && - analyzer->analy_entry) { - switch (trace->analyzer->analy_entry(trace, entry)) { - case RESULT_CONSUME: - goto check_pending; - case RESULT_CONT: - break; - default: - break; - } + switch (try_run_analyzer(trace, trace->analyzer, entry)) { + case RESULT_CONSUME: + goto check_pending; + case RESULT_CONT: + break; + default: + break; } list_add_tail(&entry->list, &analy_ctx->entries); @@ -396,7 +400,10 @@ void basic_poll_handler(void *ctx, int cpu, void *data, u32 size) .event = data, .cpu = cpu }; + trace_t *trace; + trace = get_trace_from_analy_entry(&entry); + try_run_analyzer(trace, trace->analyzer, &entry); analy_entry_handle(&entry); } @@ -457,19 +464,27 @@ out: return RESULT_CONT; } -#define FN(name) [SKB_DROP_REASON_##name] = #name, -#ifndef __DEFINE_SKB_REASON -#define __DEFINE_SKB_REASON(fn) -#endif -static char *drop_reasons[] = { - __DEFINE_SKB_REASON(FN) -}; -DEFINE_ANALYZER_ENTRY(drop, TRACE_MODE_TIMELINE_MASK | TRACE_MODE_INETL_MASK) +DEFINE_ANALYZER_ENTRY(drop, TRACE_MODE_TIMELINE_MASK | TRACE_MODE_INETL_MASK | + TRACE_MODE_DROP_MASK) { drop_event_t *event = (void *)e->event; + char *reason = NULL, *sym_str, *info; struct sym_result *sym; - char *reason = NULL; - char *info; + + reason = get_drop_reason(event->reason); + sym = parse_sym(event->location); + sym_str = sym ? sym->desc : "unknow"; + + info = malloc(1024); + info[0] = '\0'; + if (trace_ctx.mode == TRACE_MODE_DROP) { + if (trace_ctx.drop_reason) + sprintf(info, ", reason: %s, %s", reason, sym_str); + else + sprintf(info, ", %s", sym_str); + entry_set_msg(e, info); + goto out; + } put_fake_analy_ctx(e->fake_ctx); hlist_del(&e->fake_ctx->hash); @@ -477,16 +492,7 @@ DEFINE_ANALYZER_ENTRY(drop, TRACE_MODE_TIMELINE_MASK | TRACE_MODE_INETL_MASK) goto out; rule_run(e, trace, 0); - sym = parse_sym(event->location); - - if (event->reason < ARRAY_SIZE(drop_reasons)) - reason = drop_reasons[event->reason]; - - info = malloc(1024); - info[0] = '\0'; - sprintf(info, PFMT_EMPH_STR(" location")":\n\t%s", - sym ? sym->desc : "unknow"); - + sprintf(info, PFMT_EMPH_STR(" location")":\n\t%s", sym_str); if (trace_ctx.drop_reason) { sprintf_end(info, PFMT_EMPH_STR("\n drop reason")":\n\t%s", reason ?: "unknow"); @@ -560,7 +566,7 @@ DEFINE_ANALYZER_EXIT(nf, TRACE_MODE_INETL_MASK) int i = 0; msg[0] = '\0'; - sprintf(msg, "%s in chain: %s", pf_names[event->pf], + sprintf(msg, PFMT_EMPH_STR(" *%s in chain: %s*"), pf_names[event->pf], hook_names[event->pf][event->hook]); entry_set_msg(entry, msg); rule_run(entry, trace, e->event.val); @@ -599,8 +605,8 @@ DEFINE_ANALYZER_EXIT(iptable, TRACE_MODE_INETL_MASK) chain = event->chain; else chain = inet_hook_names[event->hook]; - sprintf(msg, "iptables table:%s, chain:%s", event->table, - chain); + sprintf(msg, PFMT_EMPH_STR(" *iptables table:%s, chain:%s*"), + event->table, chain); entry_set_msg(entry, msg); rule_run(entry, trace, e->event.val); diff --git a/src/analysis.h b/src/analysis.h index 3f3eda7..a44fd5f 100644 --- a/src/analysis.h +++ b/src/analysis.h @@ -176,13 +176,13 @@ static inline bool event_is_ret(int size) static inline void entry_set_extinfo(analy_entry_t *e, char *info) { e->extinfo = info; - e->status != ANALY_ENTRY_EXTINFO; + e->status |= ANALY_ENTRY_EXTINFO; } static inline void entry_set_msg(analy_entry_t *e, char *info) { e->msg = info; - e->status != ANALY_ENTRY_MSG; + e->status |= ANALY_ENTRY_MSG; } #endif diff --git a/src/dropreason.c b/src/dropreason.c new file mode 100644 index 0000000..57eafa1 --- /dev/null +++ b/src/dropreason.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#include "dropreason.h" + +#define REASON_MAX_COUNT 256 +#define REASON_MAX_LEN 32 + +static char drop_reasons[REASON_MAX_COUNT][REASON_MAX_LEN] = {}; +static int drop_reason_max; +static bool drop_reason_inited = false; + +/* check if drop reason on kfree_skb is supported */ +bool drop_reason_support() +{ + return simple_exec("cat /sys/kernel/debug/tracing/events/skb/" + "kfree_skb/format | grep NOT_SPECIFIED") == 0; +} + +static int parse_reason_enum() +{ + char name[REASON_MAX_LEN], tmp[128]; + int index = 0, pos; + FILE *f; + + f = fopen("/sys/kernel/debug/tracing/events/skb/kfree_skb/format", + "r"); + + if (!f || !fsearch(f, "__print_symbolic")) + return -1; + + while (true) { + if (!fsearch(f, "{") || + fscanf(f, "%d, \"%31[A-Z_]", &index, name) != 2) + break; + strcpy(drop_reasons[index], name); + } + drop_reason_max = index; + drop_reason_inited = true; + return 0; +} + +char *get_drop_reason(int index) +{ + if (!drop_reason_inited && parse_reason_enum()) + return NULL; + if (index <= 0 || index > drop_reason_max) + return "unknown"; + + return drop_reasons[index]; +} diff --git a/src/dropreason.h b/src/dropreason.h new file mode 100644 index 0000000..d7a2574 --- /dev/null +++ b/src/dropreason.h @@ -0,0 +1,7 @@ +#ifndef _H_SKB_DROP_REASON +#define _H_SKB_DROP_REASON + +char *get_drop_reason(int index); +bool drop_reason_support(); + +#endif diff --git a/src/nettrace.c b/src/nettrace.c index aa8e7b4..a7e3542 100644 --- a/src/nettrace.c +++ b/src/nettrace.c @@ -68,6 +68,11 @@ static void do_parse_args(int argc, char *argv[]) .type = OPTION_BOOL, .desc = "print netfilter hooks if dropping by netfilter", }, + { + .lname = "drop", .dest = &trace_args->drop, + .type = OPTION_BOOL, + .desc = "skb drop monitor mode, for replace of 'droptrace'", + }, { .type = OPTION_BLANK }, { .sname = 'v', .dest = &show_log, diff --git a/src/progs/kprobe.c b/src/progs/kprobe.c index 35c0dac..329b290 100644 --- a/src/progs/kprobe.c +++ b/src/progs/kprobe.c @@ -9,6 +9,7 @@ #include "kprobe_trace.h" +#define MODE_SKIP_LIFE_MASK (TRACE_MODE_BASIC_MASK | TRACE_MODE_DROP_MASK) #define TRACE_PREFIX __trace_ struct { @@ -75,7 +76,7 @@ static try_inline int handle_entry(void *regs, struct sk_buff *skb, event_t *e, return -1; pid = (u32)bpf_get_current_pid_tgid(); - if (ARGS_GET(trace_mode) == TRACE_MODE_BASIC) { + if (ARGS_GET(trace_mode) & MODE_SKIP_LIFE_MASK) { if (!probe_parse_skb(skb, pkt)) goto skip_life; return -1; @@ -122,7 +123,7 @@ out: static try_inline int handle_destroy(struct sk_buff *skb) { - if (ARGS_GET_CONFIG(trace_mode) != TRACE_MODE_BASIC) + if (!(ARGS_GET_CONFIG(trace_mode) & MODE_SKIP_LIFE_MASK)) bpf_map_delete_elem(&m_lookup, &skb); return 0; } diff --git a/src/progs/shared.h b/src/progs/shared.h index 10ec129..a636232 100644 --- a/src/progs/shared.h +++ b/src/progs/shared.h @@ -71,8 +71,14 @@ typedef struct __attribute__((__packed__)) { typedef enum trace_mode { TRACE_MODE_BASIC, + TRACE_MODE_DROP, TRACE_MODE_TIMELINE, TRACE_MODE_INETL, } trace_mode_t; +#define TRACE_MODE_BASIC_MASK (1 << TRACE_MODE_BASIC) +#define TRACE_MODE_TIMELINE_MASK (1 << TRACE_MODE_TIMELINE) +#define TRACE_MODE_INETL_MASK (1 << TRACE_MODE_INETL) +#define TRACE_MODE_DROP_MASK (1 << TRACE_MODE_DROP) + #endif diff --git a/src/trace.c b/src/trace.c index b62139a..060819b 100644 --- a/src/trace.c +++ b/src/trace.c @@ -6,6 +6,7 @@ #include "nettrace.h" #include "trace.h" #include "analysis.h" +#include "dropreason.h" trace_context_t trace_ctx = { .mode = TRACE_MODE_TIMELINE, @@ -183,6 +184,17 @@ static int trace_prepare_args() trace_t *trace; char *tmp, *cur; + if (args->basic) + trace_ctx.mode = TRACE_MODE_BASIC; + + if (args->intel) + trace_ctx.mode = TRACE_MODE_INETL; + + if (args->drop) { + trace_ctx.mode = TRACE_MODE_DROP; + traces = "kfree_skb"; + } + if (!traces) { trace_for_each(trace) if (trace->def) @@ -209,11 +221,10 @@ static int trace_prepare_args() free(tmp); skip_trace: - if (args->basic) - trace_ctx.mode = TRACE_MODE_BASIC; - - if (args->intel) - trace_ctx.mode = TRACE_MODE_INETL; + if (drop_reason_support()) { + trace_ctx.bpf_args.drop_reason = true; + trace_ctx.drop_reason = true; + } switch (trace_ctx.mode) { case TRACE_MODE_INETL: @@ -228,10 +239,17 @@ skip_trace: trace_group_enable("life"); break; case TRACE_MODE_BASIC: + case TRACE_MODE_DROP: + if (!trace_ctx.drop_reason) { + pr_err("skb drop reason is not support by your kernel" + ", please upgrade your kernel to 5.18+\n"); + goto err; + } break; default: goto err; } + get_drop_reason(1); if (args->ret) { switch (trace_ctx.mode) { @@ -248,12 +266,7 @@ skip_trace: } } - if (trace_drop_reason_support()) { - trace_ctx.bpf_args.drop_reason = true; - trace_ctx.drop_reason = true; - } - - trace_ctx.bpf_args.trace_mode = trace_ctx.mode; + trace_ctx.bpf_args.trace_mode = 1 << trace_ctx.mode; trace_ctx.detail = trace_ctx.bpf_args.detail; return 0; diff --git a/src/trace.h b/src/trace.h index f3fa739..e9e58aa 100644 --- a/src/trace.h +++ b/src/trace.h @@ -61,6 +61,7 @@ typedef struct trace_args { bool intel_quiet; bool intel_keep; bool basic; + bool drop; char *traces; } trace_args_t; @@ -76,10 +77,6 @@ typedef struct { struct analyzer *analyzer; } trace_ops_t; -#define TRACE_MODE_BASIC_MASK (1 << TRACE_MODE_BASIC) -#define TRACE_MODE_TIMELINE_MASK (1 << TRACE_MODE_TIMELINE) -#define TRACE_MODE_INETL_MASK (1 << TRACE_MODE_INETL) - typedef struct { trace_ops_t *ops; trace_args_t args; @@ -153,13 +150,6 @@ static inline bool trace_mode_intel() return trace_ctx.mode == TRACE_MODE_INETL; } -/* check if drop reason on kfree_skb is supported */ -static inline bool trace_drop_reason_support() -{ - return simple_exec("cat /sys/kernel/debug/tracing/events/skb/" - "kfree_skb/format | grep reason") == 0; -} - void trace_show(trace_group_t *group); void init_trace_group(); trace_group_t *search_trace_group(char *name); diff --git a/src/trace_probe.c b/src/trace_probe.c index 7123fb3..eed0b20 100644 --- a/src/trace_probe.c +++ b/src/trace_probe.c @@ -118,6 +118,7 @@ static int probe_trace_open() switch (trace_ctx.mode) { case TRACE_MODE_BASIC: + case TRACE_MODE_DROP: probe_ops.trace_poll = basic_poll_handler; break; case TRACE_MODE_INETL: -- Gitee From 41ea15c4363da0886d6f80c2f52b04c100cb55e4 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 21 Oct 2022 10:25:22 +0800 Subject: [PATCH 08/13] fix global analyzer not called error in timeline mode Lacking of the 'mode' field in probe_analyzer, it is not called anymore. Therefore, adding corresponding mode to it. Signed-off-by: Menglong Dong --- src/analysis.c | 18 +++++++++++------- src/trace.c | 5 +++++ src/trace_probe.c | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/analysis.c b/src/analysis.c index 7f4dc77..d669136 100644 --- a/src/analysis.c +++ b/src/analysis.c @@ -64,7 +64,7 @@ static inline fake_analy_ctx_t analy_fake_ctx_add(fake); get_fake_analy_ctx(fake); - pr_debug("fake ctx alloc: %llx\n", PTR2X(fake)); + pr_debug("fake ctx alloc: %llx, %llx\n", PTR2X(fake), key); return fake; } @@ -309,7 +309,7 @@ void tl_poll_handler(void *raw_ctx, int cpu, void *data, u32 size) } e = entry->event; entry->cpu = cpu; - pr_debug("create entry: %llx\n", PTR2X(entry)); + pr_debug("create entry: %llx, %llx\n", PTR2X(entry), e->key); fake = analy_fake_ctx_fetch(e->key); if (!fake) { @@ -367,7 +367,8 @@ do_ret:; } entry = analy_exit.entry; if (!entry) { - pr_err("entry for exit not found\n"); + pr_err("entry for exit not found: %llx\n", + analy_exit.event.val); return; } @@ -424,13 +425,13 @@ static inline void rule_run(analy_entry_t *entry, trace_t *trace, int ret) hit = rule->range.min < ret && rule->range.max > ret; break; case RULE_RETURN_LT: - hit =rule->expected < ret; + hit = rule->expected < ret; break; case RULE_RETURN_GT: - hit =rule->expected > ret; + hit = rule->expected > ret; break; case RULE_RETURN_NE: - hit =rule->expected != ret; + hit = rule->expected != ret; break; default: continue; @@ -506,9 +507,12 @@ DEFINE_ANALYZER_EXIT(clone, TRACE_MODE_TIMELINE_MASK | TRACE_MODE_INETL_MASK) { analy_entry_t *entry = e->entry; - if (!entry || !e->event.val) + if (!entry || !e->event.val) { + pr_err("skb clone failed\n"); goto out; + } + pr_debug("clone analyzer triggered on: %llx\n", e->event.val); analy_fake_ctx_alloc(e->event.val, entry->ctx); if (trace_mode_intel()) rule_run(entry, trace, 0); diff --git a/src/trace.c b/src/trace.c index 060819b..6f63f43 100644 --- a/src/trace.c +++ b/src/trace.c @@ -184,6 +184,11 @@ static int trace_prepare_args() trace_t *trace; char *tmp, *cur; + if (args->basic + args->intel + args->drop > 1) { + pr_err("multi-mode specified!\n"); + goto err; + } + if (args->basic) trace_ctx.mode = TRACE_MODE_BASIC; diff --git a/src/trace_probe.c b/src/trace_probe.c index eed0b20..304d479 100644 --- a/src/trace_probe.c +++ b/src/trace_probe.c @@ -204,6 +204,7 @@ static void probe_trace_ready() } analyzer_t probe_analyzer = { + .mode = TRACE_MODE_INETL_MASK | TRACE_MODE_TIMELINE_MASK, .analy_entry = probe_analy_entry, .analy_exit = probe_analy_exit, }; -- Gitee From 893d4006474e9a47d4bcedc99af18ce3baa22b0d Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 21 Oct 2022 10:33:52 +0800 Subject: [PATCH 09/13] update bash-completion for nettrace command Signed-off-by: Menglong Dong --- script/bash-completion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/bash-completion.sh b/script/bash-completion.sh index 5080186..ec17235 100644 --- a/script/bash-completion.sh +++ b/script/bash-completion.sh @@ -1,2 +1,2 @@ -complete -W '-s --saddr -d --daddr --addr -p -D --dport -S --sport -P --port -t --trace -v --detail --debug --ret --basic --intel --intel-quiet --intel-keep --hooks -h --help' nettrace +complete -W '-s --saddr --saddr6 -d --daddr --daddr6 --addr --addr6 -p -D --dport -S --sport -P --port --pid -t --trace -v --detail --debug --ret --basic --diag --diag-quiet --diag-keep --drop --hooks -h --help' nettrace complete -W '-h -s -d --addr -p --dport --sport --port -t -v --detail --stack --stack-tracer --timeline -c --ret --skb-mode --force-stack --tcp-flags -o --output' nettrace-legacy -- Gitee From 10e8c63e4960a58620104d512ba2a0e008df1340 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 21 Oct 2022 12:29:10 +0800 Subject: [PATCH 10/13] support to print timestamp in date-time format Signed-off-by: Menglong Dong --- script/bash-completion.sh | 2 +- shared/pkt_utils.c | 41 ++++++++++++++++++++++++++++++++++----- shared/pkt_utils.h | 5 +++-- src/analysis.c | 2 +- src/nettrace.c | 5 +++++ src/trace.h | 1 + 6 files changed, 47 insertions(+), 9 deletions(-) diff --git a/script/bash-completion.sh b/script/bash-completion.sh index ec17235..a96369e 100644 --- a/script/bash-completion.sh +++ b/script/bash-completion.sh @@ -1,2 +1,2 @@ -complete -W '-s --saddr --saddr6 -d --daddr --daddr6 --addr --addr6 -p -D --dport -S --sport -P --port --pid -t --trace -v --detail --debug --ret --basic --diag --diag-quiet --diag-keep --drop --hooks -h --help' nettrace +complete -W '-s --saddr --saddr6 -d --daddr --daddr6 --addr --addr6 -p -D --dport -S --sport -P --port --pid -t --trace -v --detail --debug --ret --basic --diag --diag-quiet --diag-keep --date --drop --hooks -h --help' nettrace complete -W '-h -s -d --addr -p --dport --sport --port -t -v --detail --stack --stack-tracer --timeline -c --ret --skb-mode --force-stack --tcp-flags -o --output' nettrace-legacy diff --git a/shared/pkt_utils.c b/shared/pkt_utils.c index c7f31ee..1040461 100644 --- a/shared/pkt_utils.c +++ b/shared/pkt_utils.c @@ -1,22 +1,53 @@ #include +#include +#include +#include +#include #define _LINUX_IN_H #include #include "pkt_utils.h" -int ts_print_packet(char *buf, packet_t *pkt, char *minfo) +static time_t time_offset; +static struct tm *convert_ts_to_date(u64 ts) +{ + struct tm *p; + time_t tmp; + + if (!time_offset) { + struct sysinfo s_info; + sysinfo(&s_info); + + time(&time_offset); + time_offset -= s_info.uptime; + } + + tmp = time_offset + (ts / 1000000000); + return localtime(&tmp); +} + +int ts_print_packet(char *buf, packet_t *pkt, char *minfo, + bool date_format) { static char saddr[MAX_ADDR_LENGTH], daddr[MAX_ADDR_LENGTH]; + u64 ts = pkt->ts; + struct tm *p; u8 flags, l4; int pos = 0; - u64 ts; - ts = pkt->ts; - if (ts) + if (date_format) { + p = convert_ts_to_date(ts); + BUF_FMT("[%d-%d-%d %02d:%02d:%02d.%06d] ", 1900 + p->tm_year, + 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, + p->tm_sec, ts % 1000000000 / 1000); + } else { BUF_FMT("[%llu.%06llu] ", ts / 1000000000, ts % 1000000000 / 1000); + } + if (minfo) BUF_FMT("%s", minfo); + if (!pkt->proto_l3) { BUF_FMT("unknow"); goto out; @@ -97,5 +128,5 @@ out: int base_print_packet(char *buf, packet_t *pkt) { - return ts_print_packet(buf, pkt, NULL); + return ts_print_packet(buf, pkt, NULL, false); } diff --git a/shared/pkt_utils.h b/shared/pkt_utils.h index 0d058fb..06bb828 100644 --- a/shared/pkt_utils.h +++ b/shared/pkt_utils.h @@ -14,9 +14,10 @@ pos = sprintf(buf, fmt, ##args); \ } while (0) -#define BUF_FMT(fmt, args...) pos += sprintf(buf + pos, fmt, ##args); +#define BUF_FMT(fmt, args...) pos += sprintf(buf + pos, fmt, ##args) -int ts_print_packet(char *buf, packet_t *pkt, char *minfo); +int ts_print_packet(char *buf, packet_t *pkt, char *minfo, + bool date_format); int base_print_packet(char *buf, packet_t *pkt); #endif diff --git a/src/analysis.c b/src/analysis.c index d669136..beb9274 100644 --- a/src/analysis.c +++ b/src/analysis.c @@ -164,7 +164,7 @@ static void analy_entry_handle(analy_entry_t *entry) sprintf(tinfo, "[%-20s] ", t->name); } - ts_print_packet(buf, pkt, tinfo); + ts_print_packet(buf, pkt, tinfo, trace_ctx.args.date); if (trace_ctx.mode == TRACE_MODE_BASIC) goto out; diff --git a/src/nettrace.c b/src/nettrace.c index a7e3542..da658bb 100644 --- a/src/nettrace.c +++ b/src/nettrace.c @@ -43,6 +43,11 @@ static void do_parse_args(int argc, char *argv[]) .type = OPTION_BOOL, .desc = "show extern packet info, such as pid, ifname, etc", }, + { + .lname = "date", .dest = &trace_args->date, + .type = OPTION_BOOL, + .desc = "print timestamp in date-time format", + }, { .lname = "basic", .dest = &trace_args->basic, .type = OPTION_BOOL, diff --git a/src/trace.h b/src/trace.h index e9e58aa..612e8b6 100644 --- a/src/trace.h +++ b/src/trace.h @@ -62,6 +62,7 @@ typedef struct trace_args { bool intel_keep; bool basic; bool drop; + bool date; char *traces; } trace_args_t; -- Gitee From 111ab202bc5879a37a4f8972f35a8bbf6a0a7d4a Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 21 Oct 2022 21:35:11 +0800 Subject: [PATCH 11/13] compatibility for iptables from 5.4 to 6.0 kernel version Signed-off-by: Menglong Dong --- common.mk | 6 +++--- component/sys_utils.c | 12 ++++++++++++ component/sys_utils.h | 20 ++++++++++++++++---- shared/bpf/skb_utils.h | 10 +++++++++- src/Makefile | 19 ++++++++++++++++++- src/progs/kprobe.c | 36 +++++++++++++++++++----------------- src/progs/shared.h | 21 ++++++++++++++++++++- src/trace.c | 11 ++++++----- src/trace_probe.c | 25 ++++++++++++++++--------- 9 files changed, 119 insertions(+), 41 deletions(-) diff --git a/common.mk b/common.mk index 9c3be08..e9319aa 100644 --- a/common.mk +++ b/common.mk @@ -92,12 +92,12 @@ progs/%.o: progs/%.c kheaders.h @file $@ | grep debug_info > /dev/null || (rm $@ && exit 1) %.skel.h: %.o - $(BPFTOOL) gen skeleton $< > $@ + $(BPFTOOL) gen skeleton $< $(SKEL_FLAGS) > $@ $(bpf_progs): %: %.skel.h - @echo "bpf compile success" + @: -bpf: $(bpf_progs) +bpf: $(bpf_progs) $(bpf_progs_ext) $(progs): %: %.c bpf @if [ -n "$(prog-$@)" ]; then \ diff --git a/component/sys_utils.c b/component/sys_utils.c index be56688..26592ae 100644 --- a/component/sys_utils.c +++ b/component/sys_utils.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "sys_utils.h" @@ -68,3 +69,14 @@ bool fsearch(FILE *f, char *target) } return false; } + +int kernel_version() +{ + int major, minor, patch; + struct utsname buf; + + uname(&buf); + sscanf(buf.release, "%d.%d.%d", &major, &minor, &patch); + + return kv_to_num(major, minor, patch); +} diff --git a/component/sys_utils.h b/component/sys_utils.h index 111547a..69f7fb6 100644 --- a/component/sys_utils.h +++ b/component/sys_utils.h @@ -13,10 +13,11 @@ extern int log_level; -int execf(char *output, char *fmt, ...); -int exec(char *cmd, char *output); -int liberate_l(); -bool fsearch(FILE *f, char *target); +int execf(char *output, char *fmt, ...); +int exec(char *cmd, char *output); +int liberate_l(); +bool fsearch(FILE *f, char *target); +int kernel_version(); static inline int simple_exec(char *cmd) { @@ -28,6 +29,17 @@ static inline bool file_exist(char *path) return access(path, F_OK) == 0; } +static inline int kv_to_num(int major, int minor, int patch) +{ + return (major << 16) + (minor << 8) + patch; +} + +/* compare current kernel version with the provided one */ +static inline int kv_compare(int major, int minor, int patch) +{ + return kernel_version() - kv_to_num(major, minor, patch); +} + #define pr_level(level, target, fmt, args...) \ do { \ if (level <= log_level) \ diff --git a/shared/bpf/skb_utils.h b/shared/bpf/skb_utils.h index ef9ed0c..ad2e0bb 100644 --- a/shared/bpf/skb_utils.h +++ b/shared/bpf/skb_utils.h @@ -34,11 +34,19 @@ struct { bpf_probe_read_kernel(&tmp, sizeof(src), &(src)); \ tmp; \ }) + #undef _C #ifdef COMPAT_MODE #define _C(src, a) _(src->a) +#define _CF(src, a) _(src->a) +#else +#define _C(src, a, ...) BPF_CORE_READ(src, a, ##__VA_ARGS__) +#endif + +#ifdef CORE_FULL +#define _CT(src, a, ...) BPF_CORE_READ(src, a, ##__VA_ARGS__) #else -#define _C(src, a, ...) BPF_CORE_READ(src, a, ##__VA_ARGS__) +#define _CT(src, a, ...) _(src->a) #endif #ifdef COMPAT_MODE diff --git a/src/Makefile b/src/Makefile index 89d84b7..1ad5af2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,6 @@ ROOT ?= $(abspath ../) -bpf_progs := progs/kprobe progs/tracing +bpf_progs := progs/tracing +bpf_progs_ext := progs/kprobe progs := nettrace prog-nettrace-origin = \ trace.c $(COMMON_SHARED) trace_probe.c trace_tracing.c \ @@ -19,6 +20,7 @@ COMPAT ?= $(if $(KERNEL),$(shell cat $(HEADERS)/Makefile | grep \ ifneq ($(strip $(COMPAT)),) CFLAGS += -DCOMPAT_MODE + COMPAT_MODE := 1 endif NFT_HEADER := $(HEADERS)/include/net/netfilter/nf_tables.h @@ -34,6 +36,21 @@ trace_group.c: trace.yaml progs/kprobe.c: progs/kprobe_trace.h +kprobe_gen_cmd = @make BPF_CFLAGS="$(BPF_CFLAGS) $(1)" \ + SKEL_FLAGS="name $(2)" \ + progs/kprobe.skel.h; \ + mv progs/kprobe.skel.h progs/$(2).skel.h + +ifndef COMPAT_MODE +$(bpf_progs_ext): + rm -rf progs/kprobe*.skel.h + $(call kprobe_gen_cmd,-DCORE_FULL,kprobe_core) + make progs/kprobe.skel.h +else +$(bpf_progs_ext): %: %.skel.h + @: +endif + nettrace.c: $(prog-nettrace-origin) all: $(progs) diff --git a/src/progs/kprobe.c b/src/progs/kprobe.c index 329b290..7781a55 100644 --- a/src/progs/kprobe.c +++ b/src/progs/kprobe.c @@ -244,10 +244,10 @@ DEFINE_KPROBE(ipt_do_table, 1) struct xt_table *table = (void *)PT_REGS_PARM3(ctx); nf_event_t e = { .event = { .func = func, }, - .hook = _(state->hook), + .hook = _C(state, hook), }; - bpf_probe_read(e.table, sizeof(e.table) - 1, table->name); + bpf_probe_read(e.table, sizeof(e.table) - 1, _C(table, name)); return handle_entry(ctx, skb, &e.event, sizeof(e), func); } @@ -265,8 +265,8 @@ DEFINE_KPROBE(nf_hook_slow, 1) if (handle_entry(ctx, skb, &e.event, 0, func)) return 0; - e.hook = _(state->hook); - e.pf = _(state->pf); + e.hook = _C(state, hook); + e.pf = _C(state, pf); EVENT_OUTPUT(ctx, e); return 0; @@ -277,8 +277,8 @@ on_hooks:; if (handle_entry(ctx, skb, &hooks_event.event, 0, func)) return 0; - hooks_event.hook = _(state->hook); - hooks_event.pf = _(state->pf); + hooks_event.hook = _C(state, hook); + hooks_event.pf = _C(state, pf); num = _(entries->num_hook_entries); #define COPY_HOOK(i) do { \ @@ -318,18 +318,20 @@ DEFINE_KPROBE_RAW(nft_do_chain, NULL) if (handle_entry(ctx, skb, &e.event, 0, func)) return 0; -#ifndef NFT_HIGH_VERSION - state = _(pkt->xt.state); -#else - state = _(pkt->state); -#endif - chain = (void *)PT_REGS_PARM2(ctx); - table = _(chain->table); - e.hook = _(state->hook); - e.pf = _(state->pf); + if (ARGS_GET_CONFIG(nft_high)) + state = _(((struct _nft_pktinfo_new *)pkt)->state); + else + state = _(((struct _nft_pktinfo *)pkt)->xt.state); + + chain = (void *)PT_REGS_PARM2(ctx); + table = _CT(chain, table); + e.hook = _C(state, hook); + e.pf = _C(state, pf); - bpf_probe_read_kernel_str(e.chain, sizeof(e.chain), _(chain->name)); - bpf_probe_read_kernel_str(e.table, sizeof(e.table), _(table->name)); + bpf_probe_read_kernel_str(e.chain, sizeof(e.chain), + _CT(chain, name)); + bpf_probe_read_kernel_str(e.table, sizeof(e.table), + _CT(table, name)); EVENT_OUTPUT(ctx, e); return 0; diff --git a/src/progs/shared.h b/src/progs/shared.h index a636232..3d0b03e 100644 --- a/src/progs/shared.h +++ b/src/progs/shared.h @@ -9,7 +9,8 @@ bool drop_reason; \ bool detail; \ bool hooks; \ - bool ready; + bool ready; \ + bool nft_high; #include @@ -81,4 +82,22 @@ typedef enum trace_mode { #define TRACE_MODE_INETL_MASK (1 << TRACE_MODE_INETL) #define TRACE_MODE_DROP_MASK (1 << TRACE_MODE_DROP) +struct _xt_action_param { + void *arg1; + void *arg2; + void *state; +}; + +struct _nft_pktinfo { + void *skb; + bool tprot_set; + u8 tprot; + struct _xt_action_param xt; +}; + +struct _nft_pktinfo_new { + void *skb; + void *state; +}; + #endif diff --git a/src/trace.c b/src/trace.c index 6f63f43..c3e8e77 100644 --- a/src/trace.c +++ b/src/trace.c @@ -245,11 +245,9 @@ skip_trace: break; case TRACE_MODE_BASIC: case TRACE_MODE_DROP: - if (!trace_ctx.drop_reason) { - pr_err("skb drop reason is not support by your kernel" - ", please upgrade your kernel to 5.18+\n"); - goto err; - } + if (!trace_ctx.drop_reason) + pr_warn("skb drop reason is not support by your kernel" + ", drop reason will not be printed\n"); break; default: goto err; @@ -273,6 +271,9 @@ skip_trace: trace_ctx.bpf_args.trace_mode = 1 << trace_ctx.mode; trace_ctx.detail = trace_ctx.bpf_args.detail; + /* from v5.14, the struct of nft_pktinfo changed */ + trace_ctx.bpf_args.nft_high = kv_compare(5, 14, 0) >= 0; + pr_debug("nft high version: %d\n", trace_ctx.bpf_args.nft_high); return 0; err: diff --git a/src/trace_probe.c b/src/trace_probe.c index 304d479..c43094f 100644 --- a/src/trace_probe.c +++ b/src/trace_probe.c @@ -1,5 +1,8 @@ #include "trace.h" #include "progs/kprobe.skel.h" +#ifndef COMPAT_MODE +#include "progs/kprobe_core.skel.h" +#endif #include "analysis.h" #include "nettrace.h" #include "analysis.h" @@ -94,22 +97,26 @@ err: return -1; } +#define LOAD_SKEL(name) \ + skel = (void *) name##__open(); \ + if (skel && !name##__load((void *)skel)) \ + goto load_success; \ + pr_debug("failed to load skel: " #name "\n") + static struct kprobe *skel; static int probe_trace_open() { int i = 0; - skel = kprobe__open(); - if (!skel) { - pr_err("failed to open kprobe-based eBPF\n"); - goto err; - } +#ifndef COMPAT_MODE + LOAD_SKEL(kprobe_core); +#endif + LOAD_SKEL(kprobe); - if (kprobe__load(skel)) { - pr_err("failed to load kprobe-based eBPF\n"); - goto err; - } + pr_err("failed to load kprobe-based eBPF\n"); + goto err; +load_success: bpf_set_config(skel, bss, trace_ctx.bpf_args); trace_ctx.obj = skel->obj; -- Gitee From 8c887bc9c00599fbbc2716928926de99fd2540e8 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Sat, 22 Oct 2022 21:34:24 +0800 Subject: [PATCH 12/13] update README and man for nettrace With the feature we add recently, the README and man should be updated as well. Signed-off-by: Menglong Dong --- README.md | 77 +++++++++++++++++++++++++++++----------- script/zh_CN/nettrace.8 | 66 ++++++++++++++++++++++++++++------ script/zh_CN/nettrace.md | 46 ++++++++++++++++++++++-- 3 files changed, 156 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index f8897fc..eb26cb0 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,20 @@ `nettrace`是一款基于eBPF的集网络报文跟踪(故障定位)、网络故障诊断、网络异常监控于一体的网络工具集,旨在能够提供一种更加高效、易用的方法来解决复杂场景下的网络问题。目前,其实现的功能包括: -- 报文生命周期跟踪:跟踪网络报文从进入到内核协议栈到释放/丢弃的过程中在内核中所走过的路径,实现报文整个生命周期的监控,并采集生命周期各个阶段的事件、信息。通过观察报文在内核中的路径,对于有一定内核协议栈经验的人来说可以快速、有效地发现网络问题。 +- 网络报文跟踪:跟踪网络报文从进入到内核协议栈到释放/丢弃的过程中在内核中所走过的路径,实现报文整个生命周期的监控,并采集生命周期各个阶段的事件、信息。通过观察报文在内核中的路径,对于有一定内核协议栈经验的人来说可以快速、有效地发现网络问题。 - 网络故障诊断:将以往的经验集成到工具的知识库,通过知识匹配的方式来主动诊断当前网络故障,给出诊断结果以及修复建议。该功能入手简单、易用性强,无需过多的网络经验即可进行网络问题定位。 - 网络异常监控:常态化地部署到生产环境中,主动地发现、上报环境上的网络异常。 - `droptrace`:用于跟踪、监控系统中的丢包事件的工具,点击[这里](docs/droptrace.md)查看详情介绍。该功能已被遗弃,可以使用`nettrace --drop`实现相同的功能。 ## 二、安装方法 -nettrace是采用C语言编写的基于eBPF(libbpf)的命令行工具,在使用和安装时可以用编译好的RPM包和二进制程序。需要注意的是,github上发布的RPM和二进制程序都是基于TencentOS(5.4.119内核版本)编译的,对于不支持CORE的其他版本的内核,最好下载源码编译后使用,以防止数据结构不兼容的问题。 +nettrace是采用C语言编写的基于eBPF(libbpf)的命令行工具,在使用和安装时可以用编译好的RPM包和二进制程序。 -### 2.1 RPM安装 +## 2.1 系统要求 + +**注意**:对于支持BTF特性(内核版本 >= 5.3,并且配置了`CONFIG_DEBUG_INFO_BTF=y`内核配置项)的内核,可以直接下载[releases](https://github.com/OpenCloudOS/nettrace/releases)中编译好的`nettrace-xxx-1.btf.x86_64.rpm`、`nettrace-xxx-1.btf.x86_64.deb`安装包进行安装使用,或者下载包含了二进制程序的`nettrace-xxx-1.btf.tar.bz2`压缩包;对于不支持BTF的低版本的内核,需要在对应的系统上手动编译后才能使用。 + +### 2.2 RPM/DEB安装 对于TencentOS系统,可以直接使用yum命令来进行在线安装: @@ -35,17 +39,17 @@ nettrace是采用C语言编写的基于eBPF(libbpf)的命令行工具,在 sudo yum install nettrace ``` -也可以直接从[releases](https://github.com/OpenCloudOS/nettrace/releases)中下载对应的RPM安装包,手动进行安装。 +也可以直接从[releases](https://github.com/OpenCloudOS/nettrace/releases)中下载对应的RPM/DEB安装包,手动进行安装。 -### 2.2 二进制下载 +### 2.3 二进制下载 -直接从[releases](https://github.com/OpenCloudOS/nettrace/releases)下载编译好的二进制包也是可以的,[releases](https://github.com/OpenCloudOS/nettrace/releases)中的`tar.bz2`格式的压缩包即为二进制程序。由于里面的工具采用的都是静态编译的方式,因此在内核版本支持的情况下,都是可以直接下载解压后运行的。再次提醒:对于不支持`CO-RE`模式的非`TencentOS`的内核版本,最好在对应的环境上编译后使用。 +直接从[releases](https://github.com/OpenCloudOS/nettrace/releases)下载编译好的二进制包也是可以的,[releases](https://github.com/OpenCloudOS/nettrace/releases)中的`tar.bz2`格式的压缩包即为二进制程序。由于里面的工具采用的都是静态编译的方式,因此在内核版本支持的情况下,都是可以直接下载解压后运行的。**再次提醒**:对于不支持BTF的内核版本,最好在对应的环境上编译后使用。 -### 2.3 手动编译 +### 2.4 手动编译 下面来介绍下如何在Centos、ubuntu等环境上进行nettrace工具的手动编译和安装。本工具目前在4.14/4.15/5.4/5.10/5.18等版本的内核上均进行过适配和测试,更低版本的内核暂未进行适配。 -#### 2.3.1 依赖安装 +#### 2.4.1 依赖安装 本工具在编译的时候依赖于`libelf`、`libbpf`和`bpftool`组件,`clang`和`gcc`编译工具。其中,bpftool二进制程序已经直接预编译好放到源码包的script目录中,因此可以不安装。但是对于版本较高的内核,请尽量从软件仓库安装该工具。 @@ -59,7 +63,7 @@ sudo yum install nettrace sudo apt install libelf-dev libbpf-dev linux-headers-`uname -r` clang llvm gcc linux-tools-`uname -r` linux-tools-generic ``` -注意:如果当前发行版(如ubuntu16,ubuntu18)不支持libbpf-dev,请按照下文提示手动按照libbpf-0.2版本。同时,clang版本要在10+(低版本的测试有问题,暂时还没搞定),ubuntu18+直接安装clang-10 llvm-10即可,ubuntu16需要按照[这里](https://segmentfault.com/a/1190000040827790)的教程安装更新版本的clang。 +注意:如果当前发行版(如ubuntu16,ubuntu18)不支持libbpf-dev,请按照下文提示手动安装libbpf-0.2版本。同时,clang版本要在10+(低版本的测试有问题,暂时还没搞定),ubuntu18+直接安装clang-10 llvm-10即可,ubuntu16需要按照[这里](https://segmentfault.com/a/1190000040827790)的教程安装更新版本的clang。 ##### centos @@ -78,7 +82,7 @@ cd libbpf-0.2/src make install ``` -#### 2.3.2 编译 +#### 2.4.2 编译 直接下载nettrace的源码即可进行编译安装: @@ -88,6 +92,14 @@ cd nettrace make all ``` +**注意**:对于不支持BTF的5.X版本的内核,在编译的时候需要加参数`COMPAT=1`,如下所示(4.X版本的内核会自动启用该参数): + +```shell +make COMPAT=1 all +``` + +启用该参数,eBPF程序会以BPF_PROBE_READ的方式来读取数据;否则,eBPF程序会以BPF_CORE_READ的方式来读取。 + 也可以单独编译其中的某个子工具,例如只编译nettrace命令: ```shell @@ -113,19 +125,12 @@ make VMLINUX=/home/ubuntu/kernel/vmlinux all make BPFTOOL=/usr/lib/linux-tools/5.15.0-43-generic/bpftool all ``` -需要注意,对于低版本的内核(4.x),在编译的时候需要加参数`COMPAT=1`,如下所示: -```shell -make COMPAT=1 all -``` - -该参数会强制启用内联函数的方式,会使得编译出来的二进制程序变大,但是没办法,低版本的内核必须要用内核函数的方式才能加载。 - 同时,对于`ubuntu 16.04/ubuntu 18.04`系统,其内核似乎存在BUG,即其使用的内核版本实际为4.15.18,uname看到的却是4.15.0。这导致了加载eBPF程序的时候内核版本不一致,无法加载。因此对于这种情况,可以使用KERN_VER参数来手动指定内核版本(计算方式为:`(4<<16) + (15<<8) + 18`): ```shell -make COMPAT=1 KERN_VER=266002 all +make KERN_VER=266002 all ``` -#### 2.3.3 打包 +#### 2.4.3 打包 使用命令`make rpm`可制作rpm包;使用命令`make pack`可制作二进制包(二进制程序打包到压缩包中,默认存放路径为output文件夹)。 @@ -152,6 +157,7 @@ Usage: -t, --trace enable trace group or trace --ret show function return value --detail show extern packet info, such as pid, ifname, etc + --date print timestamp in date-time format --basic use 'basic' trace mode, don't trace skb's life --diag enable 'diagnose' mode --diag-quiet only print abnormal packet @@ -169,6 +175,7 @@ Usage: - `t/trace`:要启用的跟踪模块,默认启用所有 - `ret`:跟踪和显示内核函数的返回值 - `detail`:显示跟踪详细信息,包括当前的进程、网口和CPU等信息 +- `date`:以时间格式打印(以2022-10-24 xx:xx:xx.xxxxxx格式打印),而不是时间戳 - `basic`:启用`basic`跟踪模式。默认情况下,启用的是生命周期跟踪模式。启用该模式后,会直接打印出报文所经过的内核函数/tracepoint。 - `diag`:启用诊断模式 - `diag-quiet`:只显示出现存在问题的报文,不显示正常的报文 @@ -395,7 +402,7 @@ end trace... 从这里的日志可以看出,在报文经过iptables的filter表的forward链的时候,发生了丢包。在诊断结果里,会列出所有的异常事件,一个报文跟踪可能会命中多条诊断结果。这里的诊断建议是让用户检查iptables中的规则是否存在问题。 -其中,`kfree_skb`这个跟踪点是对`drop reason`内核特性(详见droptrace中的介绍)做了适配的,可以理解为将droptrace的功能集成到了这里的诊断结果中,这里可以看出其给出的对包原因是`NETFILTER_DROP`。 +其中,`kfree_skb`这个跟踪点是对`drop reason`内核特性(详见[droptrace](docs/droptrace.md)中的介绍)做了适配的,可以理解为将droptrace的功能集成到了这里的诊断结果中,这里可以看出其给出的对包原因是`NETFILTER_DROP`。 #### 3.2.2 netfilter支持 @@ -537,3 +544,33 @@ format: print fmt: "skbaddr=%p protocol=%u location=%p reason: %s", REC->skbaddr, REC->protocol, REC->location, __print_symbolic(REC->reason, { 1, "NOT_SPECIFIED" }, { 2, "NO_SOCKET" }, { 3, "PKT_TOO_SMALL" }, { 4, "TCP_CSUM" }, { 5, "SOCKET_FILTER" }, { 6, "UDP_CSUM" }, { 7, "NETFILTER_DROP" }, { 8, "OTHERHOST" }, { 9, "IP_CSUM" }, { 10, "IP_INHDR" }, { 11, "IP_RPFILTER" }, { 12, "UNICAST_IN_L2_MULTICAST" }, { 13, "XFRM_POLICY" }, { 14, "IP_NOPROTO" }, { 15, "SOCKET_RCVBUFF" }, { 16, "PROTO_MEM" }, { 17, "TCP_MD5NOTFOUND" }, { 18, "TCP_MD5UNEXPECTED" }, { 19, "TCP_MD5FAILURE" }, { 20, "SOCKET_BACKLOG" }, { 21, "TCP_FLAGS" }, { 22, "TCP_ZEROWINDOW" }, { 23, "TCP_OLD_DATA" }, { 24, "TCP_OVERWINDOW" }, { 25, "TCP_OFOMERGE" }, { 26, "TCP_RFC7323_PAWS" }, { 27, "TCP_INVALID_SEQUENCE" }, { 28, "TCP_RESET" }, { 29, "TCP_INVALID_SYN" }, { 30, "TCP_CLOSE" }, { 31, "TCP_FASTOPEN" }, { 32, "TCP_OLD_ACK" }, { 33, "TCP_TOO_OLD_ACK" }, { 34, "TCP_ACK_UNSENT_DATA" }, { 35, "TCP_OFO_QUEUE_PRUNE" }, { 36, "TCP_OFO_DROP" }, { 37, "IP_OUTNOROUTES" }, { 38, "BPF_CGROUP_EGRESS" }, { 39, "IPV6DISABLED" }, { 40, "NEIGH_CREATEFAIL" }, { 41, "NEIGH_FAILED" }, { 42, "NEIGH_QUEUEFULL" }, { 43, "NEIGH_DEAD" }, { 44, "TC_EGRESS" }, { 45, "QDISC_DROP" }, { 46, "CPU_BACKLOG" }, { 47, "XDP" }, { 48, "TC_INGRESS" }, { 49, "UNHANDLED_PROTO" }, { 50, "SKB_CSUM" }, { 51, "SKB_GSO_SEG" }, { 52, "SKB_UCOPY_FAULT" }, { 53, "DEV_HDR" }, { 54, "DEV_READY" }, { 55, "FULL_RING" }, { 56, "NOMEM" }, { 57, "HDR_TRUNC" }, { 58, "TAP_FILTER" }, { 59, "TAP_TXFILTER" }, { 60, "ICMP_CSUM" }, { 61, "INVALID_PROTO" }, { 62, "IP_INADDRERRORS" }, { 63, "IP_INNOROUTES" }, { 64, "PKT_TOO_BIG" }, { 65, "MAX" }) ``` + +该模式下使用的效果与原先的`droptrace`完全相同,如下所示: + +```shell +nettrace --drop +begin trace... +[142.097193] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AR, reason: NOT_SPECIFIED, tcp_v4_rcv+0x81 +[142.331798] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:A, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[142.331857] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AP, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[146.136576] TCP: 127.0.0.1:43582 -> 127.0.0.1:9999 seq:3819454691, ack:0, flags:S, reason: NO_SOCKET, tcp_v4_rcv+0x81 +[146.220414] TCP: 169.254.0.138:8186 -> 172.27.0.6:40634 seq:8486084, ack:2608831141, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[146.533728] TCP: 127.0.0.1:36338 -> 127.0.0.1:56100 seq:1110580666, ack:1951926207, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[147.255946] TCP: 20.44.10.122:443 -> 192.168.255.10:42878 seq:2950381253, ack:211751623, flags:A, reason: NOT_SPECIFIED, tcp_rcv_state_process+0xe9 +``` + +同样可以使用`man dropreason`命令来查看对应的丢包原因的详细解释。对于不支持`skb drop reason`特性的内核,该模式下将不会打印丢包原因字段,效果如下所示: + +```shell +nettrace --drop +begin trace... +[2016.965295] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:AR, tcp_v4_rcv+0x50 +[2017.201315] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:A, tcp_v4_do_rcv+0x70 +[2019.041344] TCP: 176.58.124.134:37441 -> 172.27.0.6:443 seq:1160140493, ack:0, flags:S, tcp_v4_rcv+0x50 +[2021.867340] TCP: 127.0.0.1:34936 -> 127.0.0.1:9999 seq:1309795878, ack:0, flags:S, tcp_v4_rcv+0x50 +[2024.997146] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AR, tcp_v4_rcv+0x50 +[2025.235953] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:A, tcp_v4_do_rcv+0x70 +[2025.235967] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AP, tcp_v4_do_rcv+0x70 +``` + + diff --git a/script/zh_CN/nettrace.8 b/script/zh_CN/nettrace.8 index 6adf97e..b20db4b 100644 --- a/script/zh_CN/nettrace.8 +++ b/script/zh_CN/nettrace.8 @@ -52,22 +52,28 @@ nettrace \- Linux系统下的网络报文跟踪、网络问题诊断工具 \fB\fC\-\-detail\fR 显示跟踪详细信息,包括当前的进程、网口和CPU等信息 .TP +\fB\fC\-\-date\fR +以时间格式打印(以2022\-10\-24 xx:xx:xx.xxxxxx格式打印),而不是时间戳 +.TP \fB\fC\-\-basic\fR 启用\fB\fCbasic\fR跟踪模式。默认情况下,启用的是生命周期跟踪模式。启用该模式后,会直接打印 出报文所经过的内核函数/tracepoint .TP -\fB\fC\-\-intel\fR +\fB\fC\-\-diag\fR 启用诊断模式 .TP -\fB\fC\-\-intel\-quiet\fR +\fB\fC\-\-diag\-quiet\fR 只显示出现存在问题的报文,不显示正常的报文 .TP -\fB\fC\-\-intel\-keep\fR -持续跟踪。\fB\fCintel\fR模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 +\fB\fC\-\-diag\-keep\fR +持续跟踪。\fB\fCdiag\fR模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。 .TP \fB\fC\-\-hooks\fR 打印netfilter上的钩子函数 .TP +\fB\fC\-\-drop\fR +进行系统丢包监控,取代原先的\fB\fCdroptrace\fR +.TP \fB\fC\-v\fR 显示程序启动的日志信息 .TP @@ -86,7 +92,7 @@ nettrace \- Linux系统下的网络报文跟踪、网络问题诊断工具 \fInettrace \-p icmp \-s 192.168.1.8 \-\-detail\fP .SS 诊断模式 .PP -使用方式与上面的一致,加个\fB\fCintel\fR参数即可使用诊断模式。上文的生命周期模式对于使用者的 +使用方式与上面的一致,加个\fB\fCdiag\fR参数即可使用诊断模式。上文的生命周期模式对于使用者的 要求比较高,需要了解内核协议栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在 生命周期模式的基础上,提供了更加丰富的信息,使得没有网络开发经验的人也可进行复杂 网络问题的定位和分析。 @@ -103,11 +109,11 @@ nettrace \- Linux系统下的网络报文跟踪、网络问题诊断工具 .RE .PP 如果当前报文存在\fB\fCERROR\fR,那么工具会给出一定的诊断修复建议,并终止当前诊断操作。通过添 -加\fB\fCintel\-keep\fR可以在发生\fB\fCERROR\fR事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: +加\fB\fCdiag\-keep\fR可以在发生\fB\fCERROR\fR事件时不退出,继续进行跟踪分析。下面是发生异常时的日志: .PP .RS .nf -\&./nettrace \-p icmp \-\-intel \-\-saddr 192.168.122.8 +\&./nettrace \-p icmp \-\-diag \-\-saddr 192.168.122.8 begin trace... ***************** ffff889fb3c64f00 *************** [4049.295546] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 @@ -157,7 +163,45 @@ end trace... 适配的,可以理解为将droptrace的功能集成到了这里的诊断结果中,这里可以看出其给出的丢包 原因是\fB\fCNETFILTER_DROP\fR。因此,可以通过一下命令来监控内核中所有的丢包事件以及丢包原因: .PP -\fInettrace \-t kfree_skb \-\-intel \-\-intel\-keep\fP +\fInettrace \-t kfree_skb \-\-diag \-\-diag\-keep\fP +.SS 丢包监控 +.PP +使用命令\fB\fCnettrace \-\-drop\fR可以对系统中的丢包事件进行监控,对于支持内核特性 +\fB\fCskb drop reason\fR的内核,这里还会打印出丢包原因。可以通过查看 +\fB\fC/tracing/events/skb/kfree_skb/format\fR来判断当前系统是否支持该特性。 +.PP +该模式下使用的效果与原先的\fB\fCdroptrace\fR完全相同,如下所示: +.PP +.RS +.nf +nettrace \-\-drop +begin trace... +[142.097193] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AR, reason: NOT_SPECIFIED, tcp_v4_rcv+0x81 +[142.331798] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:A, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[142.331857] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AP, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[146.136576] TCP: 127.0.0.1:43582 \-> 127.0.0.1:9999 seq:3819454691, ack:0, flags:S, reason: NO_SOCKET, tcp_v4_rcv+0x81 +[146.220414] TCP: 169.254.0.138:8186 \-> 172.27.0.6:40634 seq:8486084, ack:2608831141, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[146.533728] TCP: 127.0.0.1:36338 \-> 127.0.0.1:56100 seq:1110580666, ack:1951926207, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[147.255946] TCP: 20.44.10.122:443 \-> 192.168.255.10:42878 seq:2950381253, ack:211751623, flags:A, reason: NOT_SPECIFIED, tcp_rcv_state_process+0xe9 +.fi +.RE +.PP +同样可以使用\fB\fCman dropreason\fR命令来查看对应的丢包原因的详细解释。对于不支持 +\fB\fCskb drop reason\fR特性的内核,该模式下将不会打印丢包原因字段,效果如下所示: +.PP +.RS +.nf +nettrace \-\-drop +begin trace... +[2016.965295] TCP: 162.241.189.135:45432 \-> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:AR, tcp_v4_rcv+0x50 +[2017.201315] TCP: 162.241.189.135:45432 \-> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:A, tcp_v4_do_rcv+0x70 +[2019.041344] TCP: 176.58.124.134:37441 \-> 172.27.0.6:443 seq:1160140493, ack:0, flags:S, tcp_v4_rcv+0x50 +[2021.867340] TCP: 127.0.0.1:34936 \-> 127.0.0.1:9999 seq:1309795878, ack:0, flags:S, tcp_v4_rcv+0x50 +[2024.997146] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AR, tcp_v4_rcv+0x50 +[2025.235953] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:A, tcp_v4_do_rcv+0x70 +[2025.235967] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AP, tcp_v4_do_rcv+0x70 +.fi +.RE .SS netfilter支持 .PP 网络防火墙是网络故障、网络不同发生的重灾区,因此\fB\fCnetfilter\fR工具对\fB\fCnetfilter\fR提供了 @@ -171,7 +215,7 @@ end trace... .PP .RS .nf -\&./nettrace \-p icmp \-\-intel \-\-saddr 192.168.122.8 \-\-hooks +\&./nettrace \-p icmp \-\-diag \-\-saddr 192.168.122.8 \-\-hooks begin trace... ***************** ffff889faa054500 *************** [5810.702473] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 @@ -221,7 +265,7 @@ end trace... 丢包的所有的钩子函数,这里只有\fB\fCiptables\fR一个钩子函数。 .SH REQUIREMENTS .PP -内核需要支持CONFIG\fIBPF, CONFIG\fPKPROBE功能 +内核需要支持\fB\fCCONFIG_BPF\fR, \fB\fCCONFIG_KPROBE\fR, \fB\fCCONFIG_DEBUG_INFO_BTF\fR(可选)功能 .SH OS .PP Linux @@ -231,4 +275,4 @@ Menglong Dong .SH SEE ALSO .PP .BR nettrace-legacy (8), -.BR droptrace (8) +.BR dropreason (8) diff --git a/script/zh_CN/nettrace.md b/script/zh_CN/nettrace.md index 77bf5d2..af496ba 100644 --- a/script/zh_CN/nettrace.md +++ b/script/zh_CN/nettrace.md @@ -56,6 +56,9 @@ nettrace - Linux系统下的网络报文跟踪、网络问题诊断工具 `--detail` 显示跟踪详细信息,包括当前的进程、网口和CPU等信息 +`--date` + 以时间格式打印(以2022-10-24 xx:xx:xx.xxxxxx格式打印),而不是时间戳 + `--basic` 启用`basic`跟踪模式。默认情况下,启用的是生命周期跟踪模式。启用该模式后,会直接打印 出报文所经过的内核函数/tracepoint @@ -72,6 +75,9 @@ nettrace - Linux系统下的网络报文跟踪、网络问题诊断工具 `--hooks` 打印netfilter上的钩子函数 +`--drop` + 进行系统丢包监控,取代原先的`droptrace` + `-v` 显示程序启动的日志信息 @@ -160,6 +166,41 @@ end trace... *nettrace -t kfree_skb --diag --diag-keep* +### 丢包监控 + +使用命令`nettrace --drop`可以对系统中的丢包事件进行监控,对于支持内核特性 +`skb drop reason`的内核,这里还会打印出丢包原因。可以通过查看 +`/tracing/events/skb/kfree_skb/format`来判断当前系统是否支持该特性。 + +该模式下使用的效果与原先的`droptrace`完全相同,如下所示: + +```shell +nettrace --drop +begin trace... +[142.097193] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AR, reason: NOT_SPECIFIED, tcp_v4_rcv+0x81 +[142.331798] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:A, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[142.331857] TCP: 162.241.189.135:57022 -> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AP, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83 +[146.136576] TCP: 127.0.0.1:43582 -> 127.0.0.1:9999 seq:3819454691, ack:0, flags:S, reason: NO_SOCKET, tcp_v4_rcv+0x81 +[146.220414] TCP: 169.254.0.138:8186 -> 172.27.0.6:40634 seq:8486084, ack:2608831141, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[146.533728] TCP: 127.0.0.1:36338 -> 127.0.0.1:56100 seq:1110580666, ack:1951926207, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126 +[147.255946] TCP: 20.44.10.122:443 -> 192.168.255.10:42878 seq:2950381253, ack:211751623, flags:A, reason: NOT_SPECIFIED, tcp_rcv_state_process+0xe9 +``` + +同样可以使用`man dropreason`命令来查看对应的丢包原因的详细解释。对于不支持 +`skb drop reason`特性的内核,该模式下将不会打印丢包原因字段,效果如下所示: + +```shell +nettrace --drop +begin trace... +[2016.965295] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:AR, tcp_v4_rcv+0x50 +[2017.201315] TCP: 162.241.189.135:45432 -> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:A, tcp_v4_do_rcv+0x70 +[2019.041344] TCP: 176.58.124.134:37441 -> 172.27.0.6:443 seq:1160140493, ack:0, flags:S, tcp_v4_rcv+0x50 +[2021.867340] TCP: 127.0.0.1:34936 -> 127.0.0.1:9999 seq:1309795878, ack:0, flags:S, tcp_v4_rcv+0x50 +[2024.997146] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AR, tcp_v4_rcv+0x50 +[2025.235953] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:A, tcp_v4_do_rcv+0x70 +[2025.235967] TCP: 162.241.189.135:46756 -> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AP, tcp_v4_do_rcv+0x70 +``` + ### netfilter支持 网络防火墙是网络故障、网络不同发生的重灾区,因此`netfilter`工具对`netfilter`提供了 @@ -222,7 +263,7 @@ end trace... ## REQUIREMENTS -内核需要支持CONFIG_BPF, CONFIG_KPROBE功能 +内核需要支持`CONFIG_BPF`, `CONFIG_KPROBE`, `CONFIG_DEBUG_INFO_BTF`(可选)功能 ## OS @@ -234,4 +275,5 @@ Menglong Dong ## SEE ALSO -nettrace-legacy(8) +nettrace-legacy(8), dropreason(8) + -- Gitee From 5bba31ff8dad0edca7aafa25cf0c8a7b016d17ad Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Fri, 21 Oct 2022 21:36:21 +0800 Subject: [PATCH 13/13] version: 1.2.2 Signed-off-by: Menglong Dong --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e9cb81..3d310d5 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -export VERSION = 1.2.1 +export VERSION = 1.2.2 RELEASE ?= .tl3 export RELEASE -- Gitee