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

netfilter: nf_tables: Introduce NFT_MSG_GETSETELEM_RESET

Analogous to NFT_MSG_GETOBJ_RESET, but for set elements with a timeout
or attached stateful expressions like counters or quotas - reset them
all at once. Respect a per element timeout value if present to reset the
'expires' value to.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Phil Sutter and committed by
Pablo Neira Ayuso
079cd633 45897255

+50 -20
+2
include/uapi/linux/netfilter/nf_tables.h
··· 105 105 * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes) 106 106 * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes) 107 107 * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes) 108 + * @NFT_MSG_GETSETELEM_RESET: get set elements and reset attached stateful expressions (enum nft_set_elem_attributes) 108 109 */ 109 110 enum nf_tables_msg_types { 110 111 NFT_MSG_NEWTABLE, ··· 141 140 NFT_MSG_DESTROYSETELEM, 142 141 NFT_MSG_DESTROYOBJ, 143 142 NFT_MSG_DESTROYFLOWTABLE, 143 + NFT_MSG_GETSETELEM_RESET, 144 144 NFT_MSG_MAX, 145 145 }; 146 146
+48 -20
net/netfilter/nf_tables_api.c
··· 5229 5229 5230 5230 static int nft_set_elem_expr_dump(struct sk_buff *skb, 5231 5231 const struct nft_set *set, 5232 - const struct nft_set_ext *ext) 5232 + const struct nft_set_ext *ext, 5233 + bool reset) 5233 5234 { 5234 5235 struct nft_set_elem_expr *elem_expr; 5235 5236 u32 size, num_exprs = 0; ··· 5243 5242 5244 5243 if (num_exprs == 1) { 5245 5244 expr = nft_setelem_expr_at(elem_expr, 0); 5246 - if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, false) < 0) 5245 + if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, reset) < 0) 5247 5246 return -1; 5248 5247 5249 5248 return 0; ··· 5254 5253 5255 5254 nft_setelem_expr_foreach(expr, elem_expr, size) { 5256 5255 expr = nft_setelem_expr_at(elem_expr, size); 5257 - if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, false) < 0) 5256 + if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, reset) < 0) 5258 5257 goto nla_put_failure; 5259 5258 } 5260 5259 nla_nest_end(skb, nest); ··· 5267 5266 5268 5267 static int nf_tables_fill_setelem(struct sk_buff *skb, 5269 5268 const struct nft_set *set, 5270 - const struct nft_set_elem *elem) 5269 + const struct nft_set_elem *elem, 5270 + bool reset) 5271 5271 { 5272 5272 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); 5273 5273 unsigned char *b = skb_tail_pointer(skb); 5274 5274 struct nlattr *nest; 5275 + u64 timeout = 0; 5275 5276 5276 5277 nest = nla_nest_start_noflag(skb, NFTA_LIST_ELEM); 5277 5278 if (nest == NULL) ··· 5296 5293 goto nla_put_failure; 5297 5294 5298 5295 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS) && 5299 - nft_set_elem_expr_dump(skb, set, ext)) 5296 + nft_set_elem_expr_dump(skb, set, ext, reset)) 5300 5297 goto nla_put_failure; 5301 5298 5302 5299 if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) && ··· 5309 5306 htonl(*nft_set_ext_flags(ext)))) 5310 5307 goto nla_put_failure; 5311 5308 5312 - if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) && 5313 - nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT, 5314 - nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)), 5315 - NFTA_SET_ELEM_PAD)) 5316 - goto nla_put_failure; 5309 + if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) { 5310 + timeout = *nft_set_ext_timeout(ext); 5311 + if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT, 5312 + nf_jiffies64_to_msecs(timeout), 5313 + NFTA_SET_ELEM_PAD)) 5314 + goto nla_put_failure; 5315 + } else if (set->flags & NFT_SET_TIMEOUT) { 5316 + timeout = READ_ONCE(set->timeout); 5317 + } 5317 5318 5318 5319 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { 5319 5320 u64 expires, now = get_jiffies_64(); ··· 5332 5325 nf_jiffies64_to_msecs(expires), 5333 5326 NFTA_SET_ELEM_PAD)) 5334 5327 goto nla_put_failure; 5328 + 5329 + if (reset) 5330 + *nft_set_ext_expiration(ext) = now + timeout; 5335 5331 } 5336 5332 5337 5333 if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) { ··· 5358 5348 const struct netlink_callback *cb; 5359 5349 struct nft_set_iter iter; 5360 5350 struct sk_buff *skb; 5351 + bool reset; 5361 5352 }; 5362 5353 5363 5354 static int nf_tables_dump_setelem(const struct nft_ctx *ctx, ··· 5369 5358 struct nft_set_dump_args *args; 5370 5359 5371 5360 args = container_of(iter, struct nft_set_dump_args, iter); 5372 - return nf_tables_fill_setelem(args->skb, set, elem); 5361 + return nf_tables_fill_setelem(args->skb, set, elem, args->reset); 5373 5362 } 5374 5363 5375 5364 struct nft_set_dump_ctx { ··· 5378 5367 }; 5379 5368 5380 5369 static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb, 5381 - const struct nft_set *set) 5370 + const struct nft_set *set, bool reset) 5382 5371 { 5383 5372 struct nft_set_elem_catchall *catchall; 5384 5373 u8 genmask = nft_genmask_cur(net); ··· 5393 5382 continue; 5394 5383 5395 5384 elem.priv = catchall->elem; 5396 - ret = nf_tables_fill_setelem(skb, set, &elem); 5385 + ret = nf_tables_fill_setelem(skb, set, &elem, reset); 5397 5386 break; 5398 5387 } 5399 5388 ··· 5411 5400 bool set_found = false; 5412 5401 struct nlmsghdr *nlh; 5413 5402 struct nlattr *nest; 5403 + bool reset = false; 5414 5404 u32 portid, seq; 5415 5405 int event; 5416 5406 ··· 5459 5447 if (nest == NULL) 5460 5448 goto nla_put_failure; 5461 5449 5450 + if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) 5451 + reset = true; 5452 + 5462 5453 args.cb = cb; 5463 5454 args.skb = skb; 5455 + args.reset = reset; 5464 5456 args.iter.genmask = nft_genmask_cur(net); 5465 5457 args.iter.skip = cb->args[0]; 5466 5458 args.iter.count = 0; ··· 5473 5457 set->ops->walk(&dump_ctx->ctx, set, &args.iter); 5474 5458 5475 5459 if (!args.iter.err && args.iter.count == cb->args[0]) 5476 - args.iter.err = nft_set_catchall_dump(net, skb, set); 5460 + args.iter.err = nft_set_catchall_dump(net, skb, set, reset); 5477 5461 rcu_read_unlock(); 5478 5462 5479 5463 nla_nest_end(skb, nest); ··· 5511 5495 const struct nft_ctx *ctx, u32 seq, 5512 5496 u32 portid, int event, u16 flags, 5513 5497 const struct nft_set *set, 5514 - const struct nft_set_elem *elem) 5498 + const struct nft_set_elem *elem, 5499 + bool reset) 5515 5500 { 5516 5501 struct nlmsghdr *nlh; 5517 5502 struct nlattr *nest; ··· 5533 5516 if (nest == NULL) 5534 5517 goto nla_put_failure; 5535 5518 5536 - err = nf_tables_fill_setelem(skb, set, elem); 5519 + err = nf_tables_fill_setelem(skb, set, elem, reset); 5537 5520 if (err < 0) 5538 5521 goto nla_put_failure; 5539 5522 ··· 5639 5622 } 5640 5623 5641 5624 static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, 5642 - const struct nlattr *attr) 5625 + const struct nlattr *attr, bool reset) 5643 5626 { 5644 5627 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; 5645 5628 struct nft_set_elem elem; ··· 5683 5666 return err; 5684 5667 5685 5668 err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid, 5686 - NFT_MSG_NEWSETELEM, 0, set, &elem); 5669 + NFT_MSG_NEWSETELEM, 0, set, &elem, 5670 + reset); 5687 5671 if (err < 0) 5688 5672 goto err_fill_setelem; 5689 5673 ··· 5708 5690 struct nft_set *set; 5709 5691 struct nlattr *attr; 5710 5692 struct nft_ctx ctx; 5693 + bool reset = false; 5711 5694 int rem, err = 0; 5712 5695 5713 5696 table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, ··· 5743 5724 if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) 5744 5725 return -EINVAL; 5745 5726 5727 + if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) 5728 + reset = true; 5729 + 5746 5730 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 5747 - err = nft_get_set_elem(&ctx, set, attr); 5731 + err = nft_get_set_elem(&ctx, set, attr, reset); 5748 5732 if (err < 0) { 5749 5733 NL_SET_BAD_ATTR(extack, attr); 5750 5734 break; ··· 5780 5758 flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 5781 5759 5782 5760 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags, 5783 - set, elem); 5761 + set, elem, false); 5784 5762 if (err < 0) { 5785 5763 kfree_skb(skb); 5786 5764 goto err; ··· 8732 8710 .policy = nft_set_elem_list_policy, 8733 8711 }, 8734 8712 [NFT_MSG_GETSETELEM] = { 8713 + .call = nf_tables_getsetelem, 8714 + .type = NFNL_CB_RCU, 8715 + .attr_count = NFTA_SET_ELEM_LIST_MAX, 8716 + .policy = nft_set_elem_list_policy, 8717 + }, 8718 + [NFT_MSG_GETSETELEM_RESET] = { 8735 8719 .call = nf_tables_getsetelem, 8736 8720 .type = NFNL_CB_RCU, 8737 8721 .attr_count = NFTA_SET_ELEM_LIST_MAX,