netfilter: ctnetlink: use dump structure instead of raw args

netlink_dump structure has a union of 'long args[6]' and a context
buffer as scratch space.

Convert ctnetlink to use a structure, its easier to read than the
raw 'args' usage which comes with no type checks and no readable names.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Florian Westphal 2022-02-04 13:11:45 +01:00 committed by Pablo Neira Ayuso
parent 98eee88b8d
commit 5948ed297e

View file

@ -58,6 +58,12 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
struct ctnetlink_list_dump_ctx {
struct nf_conn *last;
unsigned int cpu;
bool done;
};
static int ctnetlink_dump_tuples_proto(struct sk_buff *skb, static int ctnetlink_dump_tuples_proto(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_l4proto *l4proto) const struct nf_conntrack_l4proto *l4proto)
@ -1694,14 +1700,18 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb,
static int ctnetlink_done_list(struct netlink_callback *cb) static int ctnetlink_done_list(struct netlink_callback *cb)
{ {
if (cb->args[1]) struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx;
nf_ct_put((struct nf_conn *)cb->args[1]);
if (ctx->last)
nf_ct_put(ctx->last);
return 0; return 0;
} }
static int static int
ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying) ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
{ {
struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx;
struct nf_conn *ct, *last; struct nf_conn *ct, *last;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n; struct hlist_nulls_node *n;
@ -1712,12 +1722,12 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
struct hlist_nulls_head *list; struct hlist_nulls_head *list;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
if (cb->args[2]) if (ctx->done)
return 0; return 0;
last = (struct nf_conn *)cb->args[1]; last = ctx->last;
for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) { for (cpu = ctx->cpu; cpu < nr_cpu_ids; cpu++) {
struct ct_pcpu *pcpu; struct ct_pcpu *pcpu;
if (!cpu_possible(cpu)) if (!cpu_possible(cpu))
@ -1731,10 +1741,10 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (l3proto && nf_ct_l3num(ct) != l3proto) if (l3proto && nf_ct_l3num(ct) != l3proto)
continue; continue;
if (cb->args[1]) { if (ctx->last) {
if (ct != last) if (ct != last)
continue; continue;
cb->args[1] = 0; ctx->last = NULL;
} }
/* We can't dump extension info for the unconfirmed /* We can't dump extension info for the unconfirmed
@ -1751,19 +1761,19 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
if (res < 0) { if (res < 0) {
if (!refcount_inc_not_zero(&ct->ct_general.use)) if (!refcount_inc_not_zero(&ct->ct_general.use))
continue; continue;
cb->args[0] = cpu; ctx->cpu = cpu;
cb->args[1] = (unsigned long)ct; ctx->last = ct;
spin_unlock_bh(&pcpu->lock); spin_unlock_bh(&pcpu->lock);
goto out; goto out;
} }
} }
if (cb->args[1]) { if (ctx->last) {
cb->args[1] = 0; ctx->last = NULL;
goto restart; goto restart;
} }
spin_unlock_bh(&pcpu->lock); spin_unlock_bh(&pcpu->lock);
} }
cb->args[2] = 1; ctx->done = true;
out: out:
if (last) if (last)
nf_ct_put(last); nf_ct_put(last);
@ -3877,6 +3887,8 @@ static int __init ctnetlink_init(void)
{ {
int ret; int ret;
BUILD_BUG_ON(sizeof(struct ctnetlink_list_dump_ctx) > sizeof_field(struct netlink_callback, ctx));
ret = nfnetlink_subsys_register(&ctnl_subsys); ret = nfnetlink_subsys_register(&ctnl_subsys);
if (ret < 0) { if (ret < 0) {
pr_err("ctnetlink_init: cannot register with nfnetlink.\n"); pr_err("ctnetlink_init: cannot register with nfnetlink.\n");