diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 0e9dcc52d..44e5640c3 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -57,7 +57,8 @@ GENERATE_PERLMOD = NO #--------------------------------------------------------------------------- INCLUDE_PATH = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests" MACRO_EXPANSION = YES -PREDEFINED = bf_aligned(x)= +PREDEFINED = bf_aligned(x)= \ + DOXYGEN #--------------------------------------------------------------------------- # Configuration options related to diagram generator tools diff --git a/src/bfcli/print.c b/src/bfcli/print.c index b920dc21d..4a036f795 100644 --- a/src/bfcli/print.c +++ b/src/bfcli/print.c @@ -373,17 +373,17 @@ static void _bf_chain_log_header(const struct bf_log *log) bf_logger_get_color(BF_COLOR_LIGHT_CYAN, BF_STYLE_NORMAL), time_str, time.tv_nsec / BF_TIME_US, bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), log->rule_id, - bf_logger_get_color(BF_COLOR_DEFAULT, BF_STYLE_BOLD), log->pkt_size, + bf_logger_get_color(BF_COLOR_DEFAULT, BF_STYLE_BOLD), log->pkt.pkt_size, bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), bf_verdict_to_str((enum bf_verdict)log->verdict)); } static void _bf_chain_log_l2(const struct bf_log *log) { - struct ethhdr *ethhdr = (void *)log->l2hdr; + struct ethhdr *ethhdr = (void *)log->pkt.l2hdr; const char *ethertype; - if (!(log->headers & (1 << BF_PKTHDR_LINK))) { + if (!(log->pkt.headers & (1 << BF_PKTHDR_LINK))) { (void)fprintf(stdout, " Ethernet : \n"); return; } @@ -418,14 +418,14 @@ static void _bf_chain_log_l3(const struct bf_log *log) char dst_addr[INET6_ADDRSTRLEN]; const char *protocol; - if (!(log->headers & (1 << BF_PKTHDR_INTERNET))) { + if (!(log->pkt.headers & (1 << BF_PKTHDR_INTERNET))) { (void)fprintf(stdout, " Internet : \n"); return; } switch (log->l3_proto) { case ETH_P_IP: - iphdr = (struct iphdr *)&log->l3hdr[0]; + iphdr = (struct iphdr *)&log->pkt.l3hdr[0]; inet_ntop(AF_INET, &iphdr->saddr, src_addr, sizeof(src_addr)); inet_ntop(AF_INET, &iphdr->daddr, dst_addr, sizeof(dst_addr)); @@ -451,7 +451,7 @@ static void _bf_chain_log_l3(const struct bf_log *log) break; case ETH_P_IPV6: - ipv6hdr = (struct ipv6hdr *)log->l3hdr; + ipv6hdr = (struct ipv6hdr *)log->pkt.l3hdr; inet_ntop(AF_INET6, &ipv6hdr->saddr, src_addr, sizeof(src_addr)); inet_ntop(AF_INET6, &ipv6hdr->daddr, dst_addr, sizeof(dst_addr)); @@ -490,14 +490,14 @@ static void _bf_chain_log_l4(const struct bf_log *log) struct udphdr *udphdr; const char *tcp_flags_str; - if (!(log->headers & (1 << BF_PKTHDR_TRANSPORT))) { + if (!(log->pkt.headers & (1 << BF_PKTHDR_TRANSPORT))) { (void)fprintf(stdout, " Transport : \n"); return; } switch (log->l4_proto) { case IPPROTO_TCP: - tcphdr = (struct tcphdr *)log->l4hdr; + tcphdr = (struct tcphdr *)log->pkt.l4hdr; tcp_flags_str = _bf_tcp_flags_to_str(tcphdr); (void)fprintf(stdout, " TCP : %s%-5u%s → %s%-5u%s", @@ -522,7 +522,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_UDP: - udphdr = (struct udphdr *)log->l4hdr; + udphdr = (struct udphdr *)log->pkt.l4hdr; (void)fprintf(stdout, " UDP : %s%-5u%s → %s%-5u%s [len=%u]\n", bf_logger_get_color(BF_COLOR_LIGHT_YELLOW, BF_STYLE_BOLD), @@ -535,7 +535,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_ICMP: - icmphdr = (struct icmphdr *)log->l4hdr; + icmphdr = (struct icmphdr *)log->pkt.l4hdr; (void)fprintf(stdout, " ICMP : type=%-3u code=%-3u", icmphdr->type, icmphdr->code); @@ -550,7 +550,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_ICMPV6: - icmp6hdr = (struct icmp6hdr *)log->l4hdr; + icmp6hdr = (struct icmp6hdr *)log->pkt.l4hdr; (void)fprintf(stdout, " ICMPv6 : type=%-3u code=%-3u", icmp6hdr->icmp6_type, icmp6hdr->icmp6_code); @@ -573,12 +573,15 @@ static void _bf_chain_log_l4(const struct bf_log *log) void bfc_print_log(const struct bf_log *log) { + if (log->log_type != BF_LOG_TYPE_PACKET) + return; + _bf_chain_log_header(log); - if (log->req_headers & (1 << BF_PKTHDR_LINK)) + if (log->pkt.req_headers & (1 << BF_PKTHDR_LINK)) _bf_chain_log_l2(log); - if (log->req_headers & (1 << BF_PKTHDR_INTERNET)) + if (log->pkt.req_headers & (1 << BF_PKTHDR_INTERNET)) _bf_chain_log_l3(log); - if (log->req_headers & (1 << BF_PKTHDR_TRANSPORT)) + if (log->pkt.req_headers & (1 << BF_PKTHDR_TRANSPORT)) _bf_chain_log_l4(log); } diff --git a/src/libbpfilter/CMakeLists.txt b/src/libbpfilter/CMakeLists.txt index 47d98e674..537d21691 100644 --- a/src/libbpfilter/CMakeLists.txt +++ b/src/libbpfilter/CMakeLists.txt @@ -109,7 +109,7 @@ bf_target_add_elfstubs(libbpfilter "parse_ipv6_eh" "parse_ipv6_nh" "update_counters" - "log" + "pkt_log" "flow_hash" ) diff --git a/src/libbpfilter/bpf/log.bpf.c b/src/libbpfilter/bpf/pkt_log.bpf.c similarity index 60% rename from src/libbpfilter/bpf/log.bpf.c rename to src/libbpfilter/bpf/pkt_log.bpf.c index bdd71516f..b2a426cbf 100644 --- a/src/libbpfilter/bpf/log.bpf.c +++ b/src/libbpfilter/bpf/pkt_log.bpf.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. */ #include @@ -11,8 +11,8 @@ #include "cgen/runtime.h" -__u8 bf_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, - __u32 l3_l4_proto) +__u8 bf_pkt_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, + __u32 verdict, __u32 l3_l4_proto) { struct bf_log *log; __u16 l3_proto = (__u16)(l3_l4_proto >> 16); @@ -28,28 +28,29 @@ __u8 bf_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, log->ts = bpf_ktime_get_ns(); log->rule_id = rule_id; log->verdict = verdict; - log->pkt_size = ctx->pkt_size; - log->req_headers = headers; - log->headers = 0; log->l3_proto = bpf_ntohs(l3_proto); log->l4_proto = l4_proto; + log->log_type = BF_LOG_TYPE_PACKET; + log->pkt.pkt_size = ctx->pkt_size; + log->pkt.req_headers = headers; + log->pkt.headers = 0; if (headers & (1 << BF_PKTHDR_LINK) && ctx->l2_hdr && ctx->l2_size <= BF_L2_SLICE_LEN) { - bpf_probe_read_kernel(log->l2hdr, ctx->l2_size, ctx->l2_hdr); - log->headers |= (1 << BF_PKTHDR_LINK); + bpf_probe_read_kernel(log->pkt.l2hdr, ctx->l2_size, ctx->l2_hdr); + log->pkt.headers |= (1 << BF_PKTHDR_LINK); } if (headers & (1 << BF_PKTHDR_INTERNET) && ctx->l3_hdr && ctx->l3_size <= BF_L3_SLICE_LEN) { - bpf_probe_read_kernel(log->l3hdr, ctx->l3_size, ctx->l3_hdr); - log->headers |= (1 << BF_PKTHDR_INTERNET); + bpf_probe_read_kernel(log->pkt.l3hdr, ctx->l3_size, ctx->l3_hdr); + log->pkt.headers |= (1 << BF_PKTHDR_INTERNET); } if (headers & (1 << BF_PKTHDR_TRANSPORT) && ctx->l4_hdr && ctx->l4_size <= BF_L4_SLICE_LEN) { - bpf_probe_read_kernel(log->l4hdr, ctx->l4_size, ctx->l4_hdr); - log->headers |= (1 << BF_PKTHDR_TRANSPORT); + bpf_probe_read_kernel(log->pkt.l4hdr, ctx->l4_size, ctx->l4_hdr); + log->pkt.headers |= (1 << BF_PKTHDR_TRANSPORT); } bpf_ringbuf_submit(log, 0); diff --git a/src/libbpfilter/cgen/program.c b/src/libbpfilter/cgen/program.c index 423462ee2..85bc67f59 100644 --- a/src/libbpfilter/cgen/program.c +++ b/src/libbpfilter/cgen/program.c @@ -363,7 +363,7 @@ static int _bf_program_generate_rule(struct bf_program *program, EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16)); EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8)); - EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_LOG); + EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PKT_LOG); } if (rule->counters) { diff --git a/src/libbpfilter/include/bpfilter/elfstub.h b/src/libbpfilter/include/bpfilter/elfstub.h index 31a05ac80..1c54ee74e 100644 --- a/src/libbpfilter/include/bpfilter/elfstub.h +++ b/src/libbpfilter/include/bpfilter/elfstub.h @@ -122,7 +122,7 @@ enum bf_elfstub_id /** * Log user-requested packet headers to a ring buffer. * - * `__u8 bf_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, __u32 l3_l4_proto)` + * `__u8 bf_pkt_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, __u32 l3_l4_proto)` * * **Parameters** * - `ctx`: address of the `bf_runtime` context of the program. @@ -133,7 +133,7 @@ enum bf_elfstub_id * * **Return** 0 on success, or 1 on error. */ - BF_ELFSTUB_LOG, + BF_ELFSTUB_PKT_LOG, /** * Calculate flow hash from packet 5-tuple + IPv6 flow label. diff --git a/src/libbpfilter/include/bpfilter/runtime.h b/src/libbpfilter/include/bpfilter/runtime.h index f245bb62b..1d3de9b39 100644 --- a/src/libbpfilter/include/bpfilter/runtime.h +++ b/src/libbpfilter/include/bpfilter/runtime.h @@ -7,11 +7,24 @@ #define bf_aligned(x) __attribute__((aligned(x))) +/** + * @brief Give an anonymous union or struct a name only for Doxygen. + * + * Allows anonymous unions/structs in code while keeping Doxygen's parser happy. + */ +#ifdef DOXYGEN +#define BF_ANONYMOUS_MEMBER(name) name +#else +#define BF_ANONYMOUS_MEMBER(name) +#endif + // _Static_assert doesn't exist in C++ #ifndef __cplusplus #define static_assert _Static_assert #endif +#include + #include /** @@ -50,6 +63,9 @@ static_assert(BF_L3_SLICE_LEN % 8 == 0, static_assert(BF_L4_SLICE_LEN % 8 == 0, "BF_L4_SLICE_LEN should be aligned to 8 bytes"); +/** Size of the process name buffer, matches TASK_COMM_LEN. */ +#define BF_COMM_LEN 16 + /** * @brief Types of network packet headers. */ @@ -77,23 +93,78 @@ enum bf_pkthdr _BF_PKTHDR_MAX, }; +/** + * @brief Log entry type discriminator. + */ +enum bf_log_type +{ + /** Packet-based log entry (XDP, TC, NF, cgroup_skb). */ + BF_LOG_TYPE_PACKET, + + /** Socket address log entry (cgroup_sock_addr). */ + BF_LOG_TYPE_SOCK_ADDR, + + _BF_LOG_TYPE_MAX, +}; + +/** + * @brief Packet log payload fields (XDP, TC, NF, cgroup_skb). + */ +struct bf_log_pkt +{ + /** Total size of the packet, including the payload. */ + __u64 pkt_size; + + /** User-requested headers, as defined in the rule. */ + __u8 req_headers:4; + + /** Logged headers, as not all hooks can access all headers. */ + __u8 headers:4; + + /** Layer 2 header. */ + bf_aligned(8) __u8 l2hdr[BF_L2_SLICE_LEN]; + + /** Layer 3 header. */ + bf_aligned(8) __u8 l3hdr[BF_L3_SLICE_LEN]; + + /** Layer 4 header. */ + bf_aligned(8) __u8 l4hdr[BF_L4_SLICE_LEN]; +}; + +/** + * @brief Socket address log payload fields (cgroup_sock_addr). + */ +struct bf_log_sock_addr +{ + /** Root namespace PID (tgid) of the process. */ + __u32 pid; + + /** Destination port in host byteorder. */ + __u16 dport; + + /** Process name. */ + bf_aligned(8) __u8 comm[BF_COMM_LEN]; + + /** Source address (4 bytes for IPv4, 16 for IPv6). */ + bf_aligned(8) __u8 saddr[sizeof(struct in6_addr)]; + + /** Destination address (4 bytes for IPv4, 16 for IPv6). */ + bf_aligned(8) __u8 daddr[sizeof(struct in6_addr)]; +}; + /** * @brief Log structure published by a chain when the `log` action is hit. * * The structure is published into a log buffer by the chain, when a hit rule * has a `log` action defined. * - * Except for the raw packet headers (`l2hdr`, `l3hdr`, and `l4hdr`), all the - * values are stored in host byteorder. + * All fields are stored in host byteorder unless noted otherwise. */ struct bf_log { - /** Timestamp of the packet processing. */ + /** Timestamp of the event. */ __u64 ts; - /** Total size of the packet, including the payload. */ - __u64 pkt_size; - /** ID of the rule triggering the log. */ __u32 rule_id; @@ -106,20 +177,22 @@ struct bf_log /** Layer 4 (transport) protocol identifier. */ __u8 l4_proto; - /** User-request headers, as defined in the rule. */ - __u8 req_headers:4; - - /** Logged headers, as not all hooks can access all headers. */ - __u8 headers:4; + /** Log entry type. */ + __u8 log_type; - /** Layer 2 header. */ - bf_aligned(8) __u8 l2hdr[BF_L2_SLICE_LEN]; - - /** Layer 3 header. */ - bf_aligned(8) __u8 l3hdr[BF_L3_SLICE_LEN]; - - /** Layer 4 header. */ - bf_aligned(8) __u8 l4hdr[BF_L4_SLICE_LEN]; + /** + * Flavor-specific payload, discriminated by `log_type`. + * + * - `BF_LOG_TYPE_PACKET`: use `pkt` — raw packet headers in network + * byteorder. + * - `BF_LOG_TYPE_SOCK_ADDR`: use `sock_addr` — socket address, port, + * and process metadata. + */ + union + { + struct bf_log_pkt pkt; + struct bf_log_sock_addr sock_addr; + } BF_ANONYMOUS_MEMBER(payload); }; struct bf_ip4_lpm_key