nft monitor [ trace ] ... can now display nftables nftrace debug information. $ nft rule bridge raw prerouting add tcp dport 22 limit rate 1/second meta nftrace set 1 $ nft monitor trace trace id 834dd100 bridge packet src 5e:95:99:72:ea:c5 dst 52:54:40:a2:3f:a6 src 192.168.7.1 dst 192.168.7.11 len 88 ttl 64 id 2719 protocol 6 sport 3628 dport 22 iif eth0 trace id 834dd100 bridge raw prerouting rule verdict continue iif eth0 trace id 834dd100 rule tcp dport ssh limit rate 1/second nftrace set 1 trace id 834dd100 bridge raw prerouting policy verdict accept iif eth0 trace id 834dd100 ip filter input rule verdict jump iif br0 trace id 834dd100 rule ip saddr . tcp dport vmap { } trace id 834dd100 ip filter test rule verdict accept iif br0 trace id 834dd100 rule accept based on an initial patch from Markus Kötter. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- include/linux/netfilter/nf_tables.h | 30 +++++++++++++ src/evaluate.c | 18 ++++++++ src/netlink.c | 84 +++++++++++++++++++++++++++++++++++++ src/rule.c | 47 +++++++++++++++++---- 4 files changed, 170 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 5ebe3d8..85d739b 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -101,6 +101,7 @@ enum nf_tables_msg_types { NFT_MSG_DELSETELEM, NFT_MSG_NEWGEN, NFT_MSG_GETGEN, + NFT_MSG_TRACE, NFT_MSG_MAX, }; @@ -961,4 +962,33 @@ enum nft_gen_attributes { }; #define NFTA_GEN_MAX (__NFTA_GEN_MAX - 1) +enum nft_trace_attibutes { + NFTA_TRACE_UNSPEC, + NFTA_TRACE_CHAIN, + NFTA_TRACE_ID, + NFTA_TRACE_IIF, + NFTA_TRACE_OIF, + NFTA_TRACE_LL_HEADER, + NFTA_TRACE_LL_TYPE, + NFTA_TRACE_MARK, + NFTA_TRACE_PAYLOAD, + NFTA_TRACE_TABLE, + NFTA_TRACE_TYPE, + NFTA_TRACE_RULE_HANDLE, + NFTA_TRACE_VERDICT, + NFTA_TRACE_VLAN_TAG, + NFTA_TRACE_DEVTYPE, + __NFTA_TRACE_MAX +}; +#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1) + +enum nft_trace_types { + NFT_TRACETYPE_UNSPEC, + NFT_TRACETYPE_PACKET, + NFT_TRACETYPE_POLICY, + NFT_TRACETYPE_RETURN, + NFT_TRACETYPE_RULE, + __NFT_TRACETYPE_MAX +}; +#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1) #endif /* _LINUX_NF_TABLES_H */ diff --git a/src/evaluate.c b/src/evaluate.c index 48f071f..b1ab8e9 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2279,6 +2279,7 @@ enum { CMD_MONITOR_EVENT_ANY, CMD_MONITOR_EVENT_NEW, CMD_MONITOR_EVENT_DEL, + CMD_MONITOR_EVENT_TRACE, CMD_MONITOR_EVENT_MAX }; @@ -2320,6 +2321,21 @@ static uint32_t monitor_flags[CMD_MONITOR_EVENT_MAX][CMD_MONITOR_OBJ_MAX] = { [CMD_MONITOR_OBJ_SETS] = (1 << NFT_MSG_DELSET), [CMD_MONITOR_OBJ_ELEMS] = (1 << NFT_MSG_DELSETELEM), }, + [CMD_MONITOR_EVENT_TRACE] = { + [CMD_MONITOR_OBJ_ANY] = (1 << NFT_MSG_NEWTABLE) | + (1 << NFT_MSG_NEWCHAIN) | + (1 << NFT_MSG_NEWRULE) | + (1 << NFT_MSG_DELTABLE) | + (1 << NFT_MSG_DELCHAIN) | + (1 << NFT_MSG_DELRULE) | + (1 << NFT_MSG_TRACE), + [CMD_MONITOR_OBJ_TABLES] = (1 << NFT_MSG_NEWTABLE) | + (1 << NFT_MSG_DELTABLE), + [CMD_MONITOR_OBJ_CHAINS] = (1 << NFT_MSG_NEWCHAIN) | + (1 << NFT_MSG_DELCHAIN), + [CMD_MONITOR_OBJ_RULES] = (1 << NFT_MSG_NEWRULE) | + (1 << NFT_MSG_DELRULE), + }, }; static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd) @@ -2332,6 +2348,8 @@ static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd) event = CMD_MONITOR_EVENT_NEW; else if (strcmp(cmd->monitor->event, "destroy") == 0) event = CMD_MONITOR_EVENT_DEL; + else if (strcmp(cmd->monitor->event, "trace") == 0) + event = CMD_MONITOR_EVENT_TRACE; else { return monitor_error(ctx, cmd->monitor, "invalid event %s", cmd->monitor->event); diff --git a/src/netlink.c b/src/netlink.c index 974afb1..8ab7bbe 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -18,6 +18,7 @@ #include <stdlib.h> #include <libnftnl/table.h> +#include <libnftnl/trace.h> #include <libnftnl/chain.h> #include <libnftnl/expr.h> #include <libnftnl/set.h> @@ -33,6 +34,7 @@ #include <gmputil.h> #include <utils.h> #include <erec.h> +#include <iface.h> static struct mnl_socket *nf_sock; static struct mnl_socket *nf_mon_sock; @@ -2125,6 +2127,85 @@ static void netlink_events_cache_update(struct netlink_mon_handler *monh, } } +static void trace_print_rule(const struct nftnl_trace *nlt) +{ + const struct table *table; + uint64_t rule_handle; + struct chain *chain; + struct handle h; + + h.table = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE); + h.chain = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN); + h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY); + + if (!h.table) + return; + + table = table_lookup(&h); + if (!table) + return; + + chain = chain_lookup(table, &h); + if (!chain) + return; + + if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) { + struct rule *rule; + + rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE); + + list_for_each_entry(rule, &chain->rules, list) { + if (rule->handle.handle != rule_handle) + continue; + + printf("\ntrace id %08x rule ", nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID)); + rule_print(rule); + return; + } + } +} + +static void trace_print_if(const struct nftnl_trace *nlt, uint16_t attr, const char *str) +{ + char __name[IFNAMSIZ]; + const char *ifname; + + if (!nftnl_trace_is_set(nlt, attr)) + return; + + ifname = nft_if_indextoname(nftnl_trace_get_u32(nlt, attr), __name); + if (ifname) + printf(" %s %s", str, ifname); + else + printf(" %s %d", str, nftnl_trace_get_u32(nlt, attr)); +} + +static 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(); + + printf("trace "); + nftnl_trace_fprintf(stdout, nlt, monh->format); + + trace_print_if(nlt, NFTNL_TRACE_IIF, "iif"); + trace_print_if(nlt, NFTNL_TRACE_OIF, "oif"); + + trace_print_rule(nlt); + printf("\n"); + nftnl_trace_free(nlt); + return MNL_CB_OK; +} + static int netlink_events_cb(const struct nlmsghdr *nlh, void *data) { int ret = MNL_CB_OK; @@ -2157,6 +2238,9 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data) case NFT_MSG_DELRULE: ret = netlink_events_rule_cb(nlh, type, monh); break; + case NFT_MSG_TRACE: + ret = netlink_events_trace_cb(nlh, type, monh); + break; } fflush(stdout); diff --git a/src/rule.c b/src/rule.c index 5d3cd84..553990d 100644 --- a/src/rule.c +++ b/src/rule.c @@ -1192,27 +1192,56 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd) return 0; } -static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd) +static bool need_cache(const struct cmd *cmd) { - struct table *t; - struct set *s; - struct netlink_mon_handler monhandler; - - /* cache only needed if monitoring: + /* * - new rules in default format * - new elements */ if (((cmd->monitor->flags & (1 << NFT_MSG_NEWRULE)) && (cmd->monitor->format == NFTNL_OUTPUT_DEFAULT)) || (cmd->monitor->flags & (1 << NFT_MSG_NEWSETELEM))) - monhandler.cache_needed = true; - else - monhandler.cache_needed = false; + return true; + if (cmd->monitor->flags & (1 << NFT_MSG_TRACE)) + return true; + + return false; +} + +static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd) +{ + struct table *t; + struct set *s; + struct netlink_mon_handler monhandler; + + monhandler.cache_needed = need_cache(cmd); if (monhandler.cache_needed) { + struct rule *rule, *nrule; + struct chain *chain; + int ret; + list_for_each_entry(t, &table_list, list) { list_for_each_entry(s, &t->sets, list) s->init = set_expr_alloc(&cmd->location); + + if (!(cmd->monitor->flags & (1 << NFT_MSG_TRACE))) + continue; + + /* When tracing we'd like to translate the rule handle + * we receive in the trace messages to the actual rule + * struct to print that out. Populate rule cache now. + */ + ret = netlink_list_table(ctx, &t->handle, + &internal_location); + + if (ret != 0) /* shouldn't happen && doesn't break things too badly */ + continue; + + list_for_each_entry_safe(rule, nrule, &ctx->list, list) { + chain = chain_lookup(t, &rule->handle); + list_move_tail(&rule->list, &chain->rules); + } } } -- 2.4.10 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html