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

Configure Feed

Select the types of activity you want to include in your feed.

netfilter: nf_tables: don't store chain address on jump

Now that the rule trailer/end marker and the rcu head reside in the
same structure, we no longer need to save/restore the chain pointer
when performing/returning from a jump.

We can simply let the trace infra walk the evaluated rule until it
hits the end marker and then fetch the chain pointer from there.

When the rule is NULL (policy tracing), then chain and basechain
pointers were already identical, so just use the basechain.

This cuts size of jumpstack in half, from 256 to 128 bytes in 64bit,
scripts/stackusage says:

nf_tables_core.c:251 nft_do_chain 328 static

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
63e9bbbc d4d89e65

+44 -28
+12 -2
include/net/netfilter/nf_tables.h
··· 1046 1046 __attribute__((aligned(__alignof__(struct nft_expr)))); 1047 1047 }; 1048 1048 1049 + struct nft_rule_dp_last { 1050 + struct nft_rule_dp end; /* end of nft_rule_blob marker */ 1051 + struct rcu_head h; /* call_rcu head */ 1052 + struct nft_rule_blob *blob; /* ptr to free via call_rcu */ 1053 + const struct nft_chain *chain; /* for nftables tracing */ 1054 + }; 1055 + 1056 + static inline const struct nft_rule_dp *nft_rule_next(const struct nft_rule_dp *rule) 1057 + { 1058 + return (void *)rule + sizeof(*rule) + rule->dlen; 1059 + } 1060 + 1049 1061 struct nft_rule_blob { 1050 1062 unsigned long size; 1051 1063 unsigned char data[] ··· 1408 1396 * @packet_dumped: packet headers sent in a previous traceinfo message 1409 1397 * @pkt: pktinfo currently processed 1410 1398 * @basechain: base chain currently processed 1411 - * @chain: chain currently processed 1412 1399 * @rule: rule that was evaluated 1413 1400 * @verdict: verdict given by rule 1414 1401 */ ··· 1419 1408 u32 skbid; 1420 1409 const struct nft_pktinfo *pkt; 1421 1410 const struct nft_base_chain *basechain; 1422 - const struct nft_chain *chain; 1423 1411 const struct nft_rule_dp *rule; 1424 1412 const struct nft_verdict *verdict; 1425 1413 };
-7
net/netfilter/nf_tables_api.c
··· 2110 2110 module_put(hook->type->owner); 2111 2111 } 2112 2112 2113 - struct nft_rule_dp_last { 2114 - struct nft_rule_dp end; /* end of nft_rule_blob marker */ 2115 - struct rcu_head h; 2116 - struct nft_rule_blob *blob; 2117 - const struct nft_chain *chain; /* for tracing */ 2118 - }; 2119 - 2120 2113 static void nft_last_rule(const struct nft_chain *chain, const void *ptr) 2121 2114 { 2122 2115 struct nft_rule_dp_last *lrule;
+6 -15
net/netfilter/nf_tables_core.c
··· 42 42 #endif 43 43 44 44 static noinline void __nft_trace_packet(struct nft_traceinfo *info, 45 - const struct nft_chain *chain, 46 45 enum nft_trace_types type) 47 46 { 48 47 if (!info->trace || !info->nf_trace) 49 48 return; 50 49 51 - info->chain = chain; 52 50 info->type = type; 53 51 54 52 nft_trace_notify(info); ··· 54 56 55 57 static inline void nft_trace_packet(const struct nft_pktinfo *pkt, 56 58 struct nft_traceinfo *info, 57 - const struct nft_chain *chain, 58 59 const struct nft_rule_dp *rule, 59 60 enum nft_trace_types type) 60 61 { 61 62 if (static_branch_unlikely(&nft_trace_enabled)) { 62 63 info->nf_trace = pkt->skb->nf_trace; 63 64 info->rule = rule; 64 - __nft_trace_packet(info, chain, type); 65 + __nft_trace_packet(info, type); 65 66 } 66 67 } 67 68 ··· 108 111 } 109 112 110 113 static noinline void __nft_trace_verdict(struct nft_traceinfo *info, 111 - const struct nft_chain *chain, 112 114 const struct nft_regs *regs) 113 115 { 114 116 enum nft_trace_types type; ··· 129 133 break; 130 134 } 131 135 132 - __nft_trace_packet(info, chain, type); 136 + __nft_trace_packet(info, type); 133 137 } 134 138 135 139 static inline void nft_trace_verdict(struct nft_traceinfo *info, 136 - const struct nft_chain *chain, 137 140 const struct nft_rule_dp *rule, 138 141 const struct nft_regs *regs) 139 142 { 140 143 if (static_branch_unlikely(&nft_trace_enabled)) { 141 144 info->rule = rule; 142 - __nft_trace_verdict(info, chain, regs); 145 + __nft_trace_verdict(info, regs); 143 146 } 144 147 } 145 148 ··· 198 203 } 199 204 200 205 struct nft_jumpstack { 201 - const struct nft_chain *chain; 202 206 const struct nft_rule_dp *rule; 203 207 }; 204 208 ··· 241 247 #define nft_rule_expr_first(rule) (struct nft_expr *)&rule->data[0] 242 248 #define nft_rule_expr_next(expr) ((void *)expr) + expr->ops->size 243 249 #define nft_rule_expr_last(rule) (struct nft_expr *)&rule->data[rule->dlen] 244 - #define nft_rule_next(rule) (void *)rule + sizeof(*rule) + rule->dlen 245 250 246 251 #define nft_rule_dp_for_each_expr(expr, last, rule) \ 247 252 for ((expr) = nft_rule_expr_first(rule), (last) = nft_rule_expr_last(rule); \ ··· 295 302 nft_trace_copy_nftrace(pkt, &info); 296 303 continue; 297 304 case NFT_CONTINUE: 298 - nft_trace_packet(pkt, &info, chain, rule, 305 + nft_trace_packet(pkt, &info, rule, 299 306 NFT_TRACETYPE_RULE); 300 307 continue; 301 308 } 302 309 break; 303 310 } 304 311 305 - nft_trace_verdict(&info, chain, rule, &regs); 312 + nft_trace_verdict(&info, rule, &regs); 306 313 307 314 switch (regs.verdict.code & NF_VERDICT_MASK) { 308 315 case NF_ACCEPT: ··· 316 323 case NFT_JUMP: 317 324 if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE)) 318 325 return NF_DROP; 319 - jumpstack[stackptr].chain = chain; 320 326 jumpstack[stackptr].rule = nft_rule_next(rule); 321 327 stackptr++; 322 328 fallthrough; ··· 331 339 332 340 if (stackptr > 0) { 333 341 stackptr--; 334 - chain = jumpstack[stackptr].chain; 335 342 rule = jumpstack[stackptr].rule; 336 343 goto next_rule; 337 344 } 338 345 339 - nft_trace_packet(pkt, &info, basechain, NULL, NFT_TRACETYPE_POLICY); 346 + nft_trace_packet(pkt, &info, NULL, NFT_TRACETYPE_POLICY); 340 347 341 348 if (static_branch_unlikely(&nft_counters_enabled)) 342 349 nft_update_chain_stats(basechain, pkt);
+26 -4
net/netfilter/nf_tables_trace.c
··· 164 164 return true; 165 165 } 166 166 167 + static const struct nft_chain *nft_trace_get_chain(const struct nft_traceinfo *info) 168 + { 169 + const struct nft_rule_dp *rule = info->rule; 170 + const struct nft_rule_dp_last *last; 171 + 172 + if (!rule) 173 + return &info->basechain->chain; 174 + 175 + while (!rule->is_last) 176 + rule = nft_rule_next(rule); 177 + 178 + last = (const struct nft_rule_dp_last *)rule; 179 + 180 + if (WARN_ON_ONCE(!last->chain)) 181 + return &info->basechain->chain; 182 + 183 + return last->chain; 184 + } 185 + 167 186 void nft_trace_notify(struct nft_traceinfo *info) 168 187 { 169 188 const struct nft_pktinfo *pkt = info->pkt; 189 + const struct nft_chain *chain; 170 190 struct nlmsghdr *nlh; 171 191 struct sk_buff *skb; 172 192 unsigned int size; ··· 196 176 if (!nfnetlink_has_listeners(nft_net(pkt), NFNLGRP_NFTRACE)) 197 177 return; 198 178 179 + chain = nft_trace_get_chain(info); 180 + 199 181 size = nlmsg_total_size(sizeof(struct nfgenmsg)) + 200 - nla_total_size(strlen(info->chain->table->name)) + 201 - nla_total_size(strlen(info->chain->name)) + 182 + nla_total_size(strlen(chain->table->name)) + 183 + nla_total_size(strlen(chain->name)) + 202 184 nla_total_size_64bit(sizeof(__be64)) + /* rule handle */ 203 185 nla_total_size(sizeof(__be32)) + /* trace type */ 204 186 nla_total_size(0) + /* VERDICT, nested */ ··· 239 217 if (nla_put_u32(skb, NFTA_TRACE_ID, info->skbid)) 240 218 goto nla_put_failure; 241 219 242 - if (nla_put_string(skb, NFTA_TRACE_CHAIN, info->chain->name)) 220 + if (nla_put_string(skb, NFTA_TRACE_CHAIN, chain->name)) 243 221 goto nla_put_failure; 244 222 245 - if (nla_put_string(skb, NFTA_TRACE_TABLE, info->chain->table->name)) 223 + if (nla_put_string(skb, NFTA_TRACE_TABLE, chain->table->name)) 246 224 goto nla_put_failure; 247 225 248 226 if (nf_trace_fill_rule_info(skb, info))