Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: add trace support

This patch adds support for tracing the packet travel through
the ruleset, in a similar fashion to x_tables.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+60
+2
include/net/netfilter/nf_tables.h
··· 392 392 * @list: used internally 393 393 * @rcu_head: used internally 394 394 * @net: net namespace that this chain belongs to 395 + * @table: table that this chain belongs to 395 396 * @handle: chain handle 396 397 * @flags: bitmask of enum nft_chain_flags 397 398 * @use: number of jump references to this chain ··· 404 403 struct list_head list; 405 404 struct rcu_head rcu_head; 406 405 struct net *net; 406 + struct nft_table *table; 407 407 u64 handle; 408 408 u8 flags; 409 409 u16 use;
+1
net/netfilter/nf_tables_api.c
··· 979 979 INIT_LIST_HEAD(&chain->rules); 980 980 chain->handle = nf_tables_alloc_handle(table); 981 981 chain->net = net; 982 + chain->table = table; 982 983 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); 983 984 984 985 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
+57
net/netfilter/nf_tables_core.c
··· 19 19 #include <linux/netfilter/nf_tables.h> 20 20 #include <net/netfilter/nf_tables_core.h> 21 21 #include <net/netfilter/nf_tables.h> 22 + #include <net/netfilter/nf_log.h> 22 23 23 24 static void nft_cmp_fast_eval(const struct nft_expr *expr, 24 25 struct nft_data data[NFT_REG_MAX + 1]) ··· 64 63 struct nft_jumpstack { 65 64 const struct nft_chain *chain; 66 65 const struct nft_rule *rule; 66 + int rulenum; 67 67 }; 68 68 69 69 static inline void ··· 81 79 rcu_read_unlock_bh(); 82 80 } 83 81 82 + enum nft_trace { 83 + NFT_TRACE_RULE, 84 + NFT_TRACE_RETURN, 85 + NFT_TRACE_POLICY, 86 + }; 87 + 88 + static const char *const comments[] = { 89 + [NFT_TRACE_RULE] = "rule", 90 + [NFT_TRACE_RETURN] = "return", 91 + [NFT_TRACE_POLICY] = "policy", 92 + }; 93 + 94 + static struct nf_loginfo trace_loginfo = { 95 + .type = NF_LOG_TYPE_LOG, 96 + .u = { 97 + .log = { 98 + .level = 4, 99 + .logflags = NF_LOG_MASK, 100 + }, 101 + }, 102 + }; 103 + 104 + static inline void nft_trace_packet(const struct nft_pktinfo *pkt, 105 + const struct nft_chain *chain, 106 + int rulenum, enum nft_trace type) 107 + { 108 + struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); 109 + 110 + nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in, 111 + pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", 112 + chain->table->name, chain->name, comments[type], 113 + rulenum); 114 + } 115 + 84 116 unsigned int 85 117 nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) 86 118 { ··· 124 88 struct nft_data data[NFT_REG_MAX + 1]; 125 89 unsigned int stackptr = 0; 126 90 struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; 91 + int rulenum = 0; 127 92 /* 128 93 * Cache cursor to avoid problems in case that the cursor is updated 129 94 * while traversing the ruleset. ··· 140 103 /* This rule is not active, skip. */ 141 104 if (unlikely(rule->genmask & (1 << gencursor))) 142 105 continue; 106 + 107 + rulenum++; 143 108 144 109 nft_rule_for_each_expr(expr, last, rule) { 145 110 if (expr->ops == &nft_cmp_fast_ops) ··· 168 129 case NF_ACCEPT: 169 130 case NF_DROP: 170 131 case NF_QUEUE: 132 + if (unlikely(pkt->skb->nf_trace)) 133 + nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); 134 + 171 135 return data[NFT_REG_VERDICT].verdict; 172 136 case NFT_JUMP: 137 + if (unlikely(pkt->skb->nf_trace)) 138 + nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); 139 + 173 140 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE); 174 141 jumpstack[stackptr].chain = chain; 175 142 jumpstack[stackptr].rule = rule; 143 + jumpstack[stackptr].rulenum = rulenum; 176 144 stackptr++; 177 145 /* fall through */ 178 146 case NFT_GOTO: 179 147 chain = data[NFT_REG_VERDICT].chain; 180 148 goto do_chain; 181 149 case NFT_RETURN: 150 + if (unlikely(pkt->skb->nf_trace)) 151 + nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN); 152 + 153 + /* fall through */ 182 154 case NFT_CONTINUE: 183 155 break; 184 156 default: ··· 197 147 } 198 148 199 149 if (stackptr > 0) { 150 + if (unlikely(pkt->skb->nf_trace)) 151 + nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN); 152 + 200 153 stackptr--; 201 154 chain = jumpstack[stackptr].chain; 202 155 rule = jumpstack[stackptr].rule; 156 + rulenum = jumpstack[stackptr].rulenum; 203 157 goto next_rule; 204 158 } 205 159 nft_chain_stats(chain, pkt, jumpstack, stackptr); 160 + 161 + if (unlikely(pkt->skb->nf_trace)) 162 + nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY); 206 163 207 164 return nft_base_chain(chain)->policy; 208 165 }