From: Florian Westphal Date: Mon, 7 Jul 2025 09:47:13 +0000 (+0200) Subject: src: split monitor trace code into new trace.c X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8e03d59b5aa46b960454b4fd30541cee77125f77;p=thirdparty%2Fnftables.git src: split monitor trace code into new trace.c Preparation patch to avoid putting more trace functionality into netlink.c. Signed-off-by: Florian Westphal Reviewed-by: Pablo Neira Ayuso --- diff --git a/Makefile.am b/Makefile.am index fb64105d..ba09e7f0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -220,6 +220,7 @@ src_libnftables_la_SOURCES = \ src/misspell.c \ src/mnl.c \ src/monitor.c \ + src/trace.c \ src/netlink.c \ src/netlink_delinearize.c \ src/netlink_linearize.c \ diff --git a/include/netlink.h b/include/netlink.h index c7da6f9e..2737d570 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -227,11 +227,6 @@ struct ruleset_parse { struct cmd *cmd; }; -struct nftnl_parse_ctx; - -int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, - struct netlink_mon_handler *monh); - enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype); void netlink_linearize_init(struct netlink_linearize_ctx *lctx, diff --git a/include/trace.h b/include/trace.h new file mode 100644 index 00000000..ebebb47d --- /dev/null +++ b/include/trace.h @@ -0,0 +1,8 @@ +#ifndef NFTABLES_TRACE_H +#define NFTABLES_TRACE_H +#include + +struct netlink_mon_handler; +int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, + struct netlink_mon_handler *monh); +#endif /* NFTABLES_TRACE_H */ diff --git a/src/monitor.c b/src/monitor.c index e3e38c2a..83977907 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/src/netlink.c b/src/netlink.c index f3157d9d..e01cb56c 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include #include -#include #define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__) @@ -1964,333 +1962,3 @@ int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h) nftnl_flowtable_list_free(flowtable_cache); return err; } - -static void trace_print_hdr(const struct nftnl_trace *nlt, - struct output_ctx *octx) -{ - nft_print(octx, "trace id %08x %s ", - nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID), - family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY))); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE)) - nft_print(octx, "%s ", - nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE)); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN)) - nft_print(octx, "%s ", - nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); -} - -static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, - struct expr *lhs, struct output_ctx *octx) -{ - struct expr *rhs, *rel; - const void *data; - uint32_t len; - - data = nftnl_trace_get_data(nlt, attr, &len); - rhs = constant_expr_alloc(&netlink_location, - lhs->dtype, lhs->byteorder, - len * BITS_PER_BYTE, data); - rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs); - - expr_print(rel, octx); - nft_print(octx, " "); - expr_free(rel); -} - -static void trace_print_verdict(const struct nftnl_trace *nlt, - struct output_ctx *octx) -{ - struct expr *chain_expr = NULL; - const char *chain = NULL; - unsigned int verdict; - struct expr *expr; - - verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) { - chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET)); - chain_expr = constant_expr_alloc(&netlink_location, - &string_type, - BYTEORDER_HOST_ENDIAN, - strlen(chain) * BITS_PER_BYTE, - chain); - } - expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr); - - nft_print(octx, "verdict "); - expr_print(expr, octx); - expr_free(expr); -} - -static void trace_print_policy(const struct nftnl_trace *nlt, - struct output_ctx *octx) -{ - unsigned int policy; - struct expr *expr; - - policy = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY); - - expr = verdict_expr_alloc(&netlink_location, policy, NULL); - - nft_print(octx, "policy "); - expr_print(expr, octx); - expr_free(expr); -} - -static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt, - uint64_t rule_handle, - struct nft_cache *cache) -{ - struct chain *chain; - struct table *table; - struct handle h; - - h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); - h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE); - h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN); - - if (!h.table.name) - return NULL; - - table = table_cache_find(&cache->table_cache, h.table.name, h.family); - if (!table) - return NULL; - - chain = chain_cache_find(table, h.chain.name); - if (!chain) - return NULL; - - return rule_lookup(chain, rule_handle); -} - -static void trace_print_rule(const struct nftnl_trace *nlt, - struct output_ctx *octx, struct nft_cache *cache) -{ - uint64_t rule_handle; - struct rule *rule; - - rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE); - rule = trace_lookup_rule(nlt, rule_handle, cache); - - trace_print_hdr(nlt, octx); - - if (rule) { - nft_print(octx, "rule "); - rule_print(rule, octx); - } else { - nft_print(octx, "unknown rule handle %" PRIu64, rule_handle); - } - - nft_print(octx, " ("); - trace_print_verdict(nlt, octx); - nft_print(octx, ")\n"); -} - -static void trace_gen_stmts(struct list_head *stmts, - struct proto_ctx *ctx, struct payload_dep_ctx *pctx, - const struct nftnl_trace *nlt, unsigned int attr, - enum proto_bases base) -{ - struct list_head unordered = LIST_HEAD_INIT(unordered); - struct list_head list; - struct expr *rel, *lhs, *rhs, *tmp, *nexpr; - struct stmt *stmt; - const struct proto_desc *desc; - const void *hdr; - uint32_t hlen; - unsigned int n; - - if (!nftnl_trace_is_set(nlt, attr)) - return; - hdr = nftnl_trace_get_data(nlt, attr, &hlen); - - lhs = payload_expr_alloc(&netlink_location, NULL, 0); - payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE); - rhs = constant_expr_alloc(&netlink_location, - &invalid_type, BYTEORDER_INVALID, - hlen * BITS_PER_BYTE, hdr); - -restart: - init_list_head(&list); - payload_expr_expand(&list, lhs, ctx); - expr_free(lhs); - - desc = NULL; - list_for_each_entry_safe(lhs, nexpr, &list, list) { - if (desc && desc != ctx->protocol[base].desc) { - /* Chained protocols */ - lhs->payload.offset = 0; - if (ctx->protocol[base].desc == NULL) - break; - goto restart; - } - - tmp = constant_expr_splice(rhs, lhs->len); - expr_set_type(tmp, lhs->dtype, lhs->byteorder); - if (tmp->byteorder == BYTEORDER_HOST_ENDIAN) - mpz_switch_byteorder(tmp->value, tmp->len / BITS_PER_BYTE); - - /* Skip unknown and filtered expressions */ - desc = lhs->payload.desc; - if (lhs->dtype == &invalid_type || - lhs->payload.tmpl == &proto_unknown_template || - desc->checksum_key == payload_hdr_field(lhs) || - desc->format.filter & (1 << payload_hdr_field(lhs))) { - expr_free(lhs); - expr_free(tmp); - continue; - } - - rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp); - stmt = expr_stmt_alloc(&rel->location, rel); - list_add_tail(&stmt->list, &unordered); - - desc = ctx->protocol[base].desc; - relational_expr_pctx_update(ctx, rel); - } - - expr_free(rhs); - - n = 0; -next: - list_for_each_entry(stmt, &unordered, list) { - enum proto_bases b = base; - - rel = stmt->expr; - lhs = rel->left; - - /* Move statements to result list in defined order */ - desc = lhs->payload.desc; - if (desc->format.order[n] && - desc->format.order[n] != payload_hdr_field(lhs)) - continue; - - list_move_tail(&stmt->list, stmts); - n++; - - if (payload_is_stacked(desc, rel)) - b--; - - /* Don't strip 'icmp type' from payload dump. */ - if (pctx->icmp_type == 0) - payload_dependency_kill(pctx, lhs, ctx->family); - if (lhs->flags & EXPR_F_PROTOCOL) - payload_dependency_store(pctx, stmt, b); - - goto next; - } -} - -static void trace_print_packet(const struct nftnl_trace *nlt, - struct output_ctx *octx) -{ - struct list_head stmts = LIST_HEAD_INIT(stmts); - const struct proto_desc *ll_desc; - struct payload_dep_ctx pctx = {}; - struct proto_ctx ctx; - uint16_t dev_type; - uint32_t nfproto; - struct stmt *stmt, *next; - - trace_print_hdr(nlt, octx); - - nft_print(octx, "packet: "); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF)) - trace_print_expr(nlt, NFTNL_TRACE_IIF, - meta_expr_alloc(&netlink_location, - NFT_META_IIF), octx); - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF)) - trace_print_expr(nlt, NFTNL_TRACE_OIF, - meta_expr_alloc(&netlink_location, - NFT_META_OIF), octx); - - proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false); - ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc; - if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) && - nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) { - nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO); - - proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, NULL); - proto_ctx_update(&ctx, PROTO_BASE_NETWORK_HDR, &netlink_location, - proto_find_upper(ll_desc, nfproto)); - } - if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL && - nftnl_trace_is_set(nlt, NFTNL_TRACE_IIFTYPE)) { - dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE); - proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, - proto_dev_desc(dev_type)); - } - - trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER, - PROTO_BASE_LL_HDR); - trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER, - PROTO_BASE_NETWORK_HDR); - trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER, - PROTO_BASE_TRANSPORT_HDR); - - list_for_each_entry_safe(stmt, next, &stmts, list) { - stmt_print(stmt, octx); - nft_print(octx, " "); - stmt_free(stmt); - } - nft_print(octx, "\n"); -} - -int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, - struct netlink_mon_handler *monh) -{ - struct nftnl_trace *nlt; - - assert(type == NFT_MSG_TRACE); - - nlt = nftnl_trace_alloc(); - if (!nlt) - memory_allocation_error(); - - if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0) - netlink_abi_error(); - - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) || - nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) - trace_print_packet(nlt, &monh->ctx->nft->output); - - switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) { - case NFT_TRACETYPE_RULE: - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) - trace_print_rule(nlt, &monh->ctx->nft->output, - &monh->ctx->nft->cache); - break; - case NFT_TRACETYPE_POLICY: - trace_print_hdr(nlt, &monh->ctx->nft->output); - - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_POLICY)) { - trace_print_policy(nlt, &monh->ctx->nft->output); - nft_mon_print(monh, " "); - } - - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) - trace_print_expr(nlt, NFTNL_TRACE_MARK, - meta_expr_alloc(&netlink_location, - NFT_META_MARK), - &monh->ctx->nft->output); - nft_mon_print(monh, "\n"); - break; - case NFT_TRACETYPE_RETURN: - trace_print_hdr(nlt, &monh->ctx->nft->output); - - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) { - trace_print_verdict(nlt, &monh->ctx->nft->output); - nft_mon_print(monh, " "); - } - - if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) - trace_print_expr(nlt, NFTNL_TRACE_MARK, - meta_expr_alloc(&netlink_location, - NFT_META_MARK), - &monh->ctx->nft->output); - nft_mon_print(monh, "\n"); - break; - } - - nftnl_trace_free(nlt); - return MNL_CB_OK; -} diff --git a/src/trace.c b/src/trace.c new file mode 100644 index 00000000..a7cc8ff0 --- /dev/null +++ b/src/trace.c @@ -0,0 +1,353 @@ +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__) + +static void trace_print_hdr(const struct nftnl_trace *nlt, + struct output_ctx *octx) +{ + nft_print(octx, "trace id %08x %s ", + nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID), + family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY))); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE)) + nft_print(octx, "%s ", + nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE)); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN)) + nft_print(octx, "%s ", + nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN)); +} + +static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr, + struct expr *lhs, struct output_ctx *octx) +{ + struct expr *rhs, *rel; + const void *data; + uint32_t len; + + data = nftnl_trace_get_data(nlt, attr, &len); + rhs = constant_expr_alloc(&netlink_location, + lhs->dtype, lhs->byteorder, + len * BITS_PER_BYTE, data); + rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs); + + expr_print(rel, octx); + nft_print(octx, " "); + expr_free(rel); +} + +static void trace_print_verdict(const struct nftnl_trace *nlt, + struct output_ctx *octx) +{ + struct expr *chain_expr = NULL; + const char *chain = NULL; + unsigned int verdict; + struct expr *expr; + + verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) { + chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET)); + chain_expr = constant_expr_alloc(&netlink_location, + &string_type, + BYTEORDER_HOST_ENDIAN, + strlen(chain) * BITS_PER_BYTE, + chain); + } + expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr); + + nft_print(octx, "verdict "); + expr_print(expr, octx); + expr_free(expr); +} + +static void trace_print_policy(const struct nftnl_trace *nlt, + struct output_ctx *octx) +{ + unsigned int policy; + struct expr *expr; + + policy = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY); + + expr = verdict_expr_alloc(&netlink_location, policy, NULL); + + nft_print(octx, "policy "); + expr_print(expr, octx); + expr_free(expr); +} + +static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt, + uint64_t rule_handle, + struct nft_cache *cache) +{ + struct chain *chain; + struct table *table; + struct handle h; + + h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); + h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE); + h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN); + + if (!h.table.name) + return NULL; + + table = table_cache_find(&cache->table_cache, h.table.name, h.family); + if (!table) + return NULL; + + chain = chain_cache_find(table, h.chain.name); + if (!chain) + return NULL; + + return rule_lookup(chain, rule_handle); +} + +static void trace_print_rule(const struct nftnl_trace *nlt, + struct output_ctx *octx, struct nft_cache *cache) +{ + uint64_t rule_handle; + struct rule *rule; + + rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE); + rule = trace_lookup_rule(nlt, rule_handle, cache); + + trace_print_hdr(nlt, octx); + + if (rule) { + nft_print(octx, "rule "); + rule_print(rule, octx); + } else { + nft_print(octx, "unknown rule handle %" PRIu64, rule_handle); + } + + nft_print(octx, " ("); + trace_print_verdict(nlt, octx); + nft_print(octx, ")\n"); +} + +static void trace_gen_stmts(struct list_head *stmts, + struct proto_ctx *ctx, struct payload_dep_ctx *pctx, + const struct nftnl_trace *nlt, unsigned int attr, + enum proto_bases base) +{ + struct list_head unordered = LIST_HEAD_INIT(unordered); + struct list_head list; + struct expr *rel, *lhs, *rhs, *tmp, *nexpr; + struct stmt *stmt; + const struct proto_desc *desc; + const void *hdr; + uint32_t hlen; + unsigned int n; + + if (!nftnl_trace_is_set(nlt, attr)) + return; + hdr = nftnl_trace_get_data(nlt, attr, &hlen); + + lhs = payload_expr_alloc(&netlink_location, NULL, 0); + payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE); + rhs = constant_expr_alloc(&netlink_location, + &invalid_type, BYTEORDER_INVALID, + hlen * BITS_PER_BYTE, hdr); + +restart: + init_list_head(&list); + payload_expr_expand(&list, lhs, ctx); + expr_free(lhs); + + desc = NULL; + list_for_each_entry_safe(lhs, nexpr, &list, list) { + if (desc && desc != ctx->protocol[base].desc) { + /* Chained protocols */ + lhs->payload.offset = 0; + if (ctx->protocol[base].desc == NULL) + break; + goto restart; + } + + tmp = constant_expr_splice(rhs, lhs->len); + expr_set_type(tmp, lhs->dtype, lhs->byteorder); + if (tmp->byteorder == BYTEORDER_HOST_ENDIAN) + mpz_switch_byteorder(tmp->value, tmp->len / BITS_PER_BYTE); + + /* Skip unknown and filtered expressions */ + desc = lhs->payload.desc; + if (lhs->dtype == &invalid_type || + lhs->payload.tmpl == &proto_unknown_template || + desc->checksum_key == payload_hdr_field(lhs) || + desc->format.filter & (1 << payload_hdr_field(lhs))) { + expr_free(lhs); + expr_free(tmp); + continue; + } + + rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp); + stmt = expr_stmt_alloc(&rel->location, rel); + list_add_tail(&stmt->list, &unordered); + + desc = ctx->protocol[base].desc; + relational_expr_pctx_update(ctx, rel); + } + + expr_free(rhs); + + n = 0; +next: + list_for_each_entry(stmt, &unordered, list) { + enum proto_bases b = base; + + rel = stmt->expr; + lhs = rel->left; + + /* Move statements to result list in defined order */ + desc = lhs->payload.desc; + if (desc->format.order[n] && + desc->format.order[n] != payload_hdr_field(lhs)) + continue; + + list_move_tail(&stmt->list, stmts); + n++; + + if (payload_is_stacked(desc, rel)) + b--; + + /* Don't strip 'icmp type' from payload dump. */ + if (pctx->icmp_type == 0) + payload_dependency_kill(pctx, lhs, ctx->family); + if (lhs->flags & EXPR_F_PROTOCOL) + payload_dependency_store(pctx, stmt, b); + + goto next; + } +} + +static void trace_print_packet(const struct nftnl_trace *nlt, + struct output_ctx *octx) +{ + struct list_head stmts = LIST_HEAD_INIT(stmts); + const struct proto_desc *ll_desc; + struct payload_dep_ctx pctx = {}; + struct proto_ctx ctx; + uint16_t dev_type; + uint32_t nfproto; + struct stmt *stmt, *next; + + trace_print_hdr(nlt, octx); + + nft_print(octx, "packet: "); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF)) + trace_print_expr(nlt, NFTNL_TRACE_IIF, + meta_expr_alloc(&netlink_location, + NFT_META_IIF), octx); + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF)) + trace_print_expr(nlt, NFTNL_TRACE_OIF, + meta_expr_alloc(&netlink_location, + NFT_META_OIF), octx); + + proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false); + ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc; + if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) && + nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) { + nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO); + + proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, NULL); + proto_ctx_update(&ctx, PROTO_BASE_NETWORK_HDR, &netlink_location, + proto_find_upper(ll_desc, nfproto)); + } + if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL && + nftnl_trace_is_set(nlt, NFTNL_TRACE_IIFTYPE)) { + dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE); + proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, + proto_dev_desc(dev_type)); + } + + trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER, + PROTO_BASE_LL_HDR); + trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER, + PROTO_BASE_NETWORK_HDR); + trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER, + PROTO_BASE_TRANSPORT_HDR); + + list_for_each_entry_safe(stmt, next, &stmts, list) { + stmt_print(stmt, octx); + nft_print(octx, " "); + stmt_free(stmt); + } + nft_print(octx, "\n"); +} + +int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type, + struct netlink_mon_handler *monh) +{ + struct nftnl_trace *nlt; + + assert(type == NFT_MSG_TRACE); + + nlt = nftnl_trace_alloc(); + if (!nlt) + memory_allocation_error(); + + if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0) + netlink_abi_error(); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) || + nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER)) + trace_print_packet(nlt, &monh->ctx->nft->output); + + switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) { + case NFT_TRACETYPE_RULE: + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) + trace_print_rule(nlt, &monh->ctx->nft->output, + &monh->ctx->nft->cache); + break; + case NFT_TRACETYPE_POLICY: + trace_print_hdr(nlt, &monh->ctx->nft->output); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_POLICY)) { + trace_print_policy(nlt, &monh->ctx->nft->output); + nft_mon_print(monh, " "); + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) + trace_print_expr(nlt, NFTNL_TRACE_MARK, + meta_expr_alloc(&netlink_location, + NFT_META_MARK), + &monh->ctx->nft->output); + nft_mon_print(monh, "\n"); + break; + case NFT_TRACETYPE_RETURN: + trace_print_hdr(nlt, &monh->ctx->nft->output); + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) { + trace_print_verdict(nlt, &monh->ctx->nft->output); + nft_mon_print(monh, " "); + } + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK)) + trace_print_expr(nlt, NFTNL_TRACE_MARK, + meta_expr_alloc(&netlink_location, + NFT_META_MARK), + &monh->ctx->nft->output); + nft_mon_print(monh, "\n"); + break; + } + + nftnl_trace_free(nlt); + return MNL_CB_OK; +}