Skip to content

Commit e4188f8

Browse files
ummakynesgregkh
authored andcommitted
netfilter: nf_tables: integrate pipapo into commit protocol
[ Upstream commit 212ed75 ] The pipapo set backend follows copy-on-update approach, maintaining one clone of the existing datastructure that is being updated. The clone and current datastructures are swapped via rcu from the commit step. The existing integration with the commit protocol is flawed because there is no operation to clean up the clone if the transaction is aborted. Moreover, the datastructure swap happens on set element activation. This patch adds two new operations for sets: commit and abort, these new operations are invoked from the commit and abort steps, after the transactions have been digested, and it updates the pipapo set backend to use it. This patch adds a new ->pending_update field to sets to maintain a list of sets that require this new commit and abort operations. Fixes: 3c4287f ("nf_tables: Add set type for arbitrary concatenation of ranges") Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 4da9d4e commit e4188f8

File tree

3 files changed

+99
-16
lines changed

3 files changed

+99
-16
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ struct nft_set_ops {
427427
const struct nft_set *set,
428428
const struct nft_set_elem *elem,
429429
unsigned int flags);
430-
430+
void (*commit)(const struct nft_set *set);
431+
void (*abort)(const struct nft_set *set);
431432
u64 (*privsize)(const struct nlattr * const nla[],
432433
const struct nft_set_desc *desc);
433434
bool (*estimate)(const struct nft_set_desc *desc,
@@ -522,6 +523,7 @@ struct nft_set {
522523
u16 policy;
523524
u16 udlen;
524525
unsigned char *udata;
526+
struct list_head pending_update;
525527
/* runtime data below here */
526528
const struct nft_set_ops *ops ____cacheline_aligned;
527529
u16 flags:14,

net/netfilter/nf_tables_api.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4633,6 +4633,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
46334633

46344634
set->num_exprs = num_exprs;
46354635
set->handle = nf_tables_alloc_handle(table);
4636+
INIT_LIST_HEAD(&set->pending_update);
46364637

46374638
err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
46384639
if (err < 0)
@@ -8786,10 +8787,25 @@ static void nf_tables_commit_audit_log(struct list_head *adl, u32 generation)
87868787
}
87878788
}
87888789

8790+
static void nft_set_commit_update(struct list_head *set_update_list)
8791+
{
8792+
struct nft_set *set, *next;
8793+
8794+
list_for_each_entry_safe(set, next, set_update_list, pending_update) {
8795+
list_del_init(&set->pending_update);
8796+
8797+
if (!set->ops->commit)
8798+
continue;
8799+
8800+
set->ops->commit(set);
8801+
}
8802+
}
8803+
87898804
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
87908805
{
87918806
struct nftables_pernet *nft_net = nft_pernet(net);
87928807
struct nft_trans *trans, *next;
8808+
LIST_HEAD(set_update_list);
87938809
struct nft_trans_elem *te;
87948810
struct nft_chain *chain;
87958811
struct nft_table *table;
@@ -8948,6 +8964,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
89488964
nf_tables_setelem_notify(&trans->ctx, te->set,
89498965
&te->elem,
89508966
NFT_MSG_NEWSETELEM);
8967+
if (te->set->ops->commit &&
8968+
list_empty(&te->set->pending_update)) {
8969+
list_add_tail(&te->set->pending_update,
8970+
&set_update_list);
8971+
}
89518972
nft_trans_destroy(trans);
89528973
break;
89538974
case NFT_MSG_DELSETELEM:
@@ -8961,6 +8982,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
89618982
atomic_dec(&te->set->nelems);
89628983
te->set->ndeact--;
89638984
}
8985+
if (te->set->ops->commit &&
8986+
list_empty(&te->set->pending_update)) {
8987+
list_add_tail(&te->set->pending_update,
8988+
&set_update_list);
8989+
}
89648990
break;
89658991
case NFT_MSG_NEWOBJ:
89668992
if (nft_trans_obj_update(trans)) {
@@ -9021,6 +9047,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90219047
}
90229048
}
90239049

9050+
nft_set_commit_update(&set_update_list);
9051+
90249052
nft_commit_notify(net, NETLINK_CB(skb).portid);
90259053
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
90269054
nf_tables_commit_audit_log(&adl, nft_net->base_seq);
@@ -9077,10 +9105,25 @@ static void nf_tables_abort_release(struct nft_trans *trans)
90779105
kfree(trans);
90789106
}
90799107

9108+
static void nft_set_abort_update(struct list_head *set_update_list)
9109+
{
9110+
struct nft_set *set, *next;
9111+
9112+
list_for_each_entry_safe(set, next, set_update_list, pending_update) {
9113+
list_del_init(&set->pending_update);
9114+
9115+
if (!set->ops->abort)
9116+
continue;
9117+
9118+
set->ops->abort(set);
9119+
}
9120+
}
9121+
90809122
static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
90819123
{
90829124
struct nftables_pernet *nft_net = nft_pernet(net);
90839125
struct nft_trans *trans, *next;
9126+
LIST_HEAD(set_update_list);
90849127
struct nft_trans_elem *te;
90859128

90869129
if (action == NFNL_ABORT_VALIDATE &&
@@ -9178,6 +9221,12 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
91789221
nft_setelem_remove(net, te->set, &te->elem);
91799222
if (!nft_setelem_is_catchall(te->set, &te->elem))
91809223
atomic_dec(&te->set->nelems);
9224+
9225+
if (te->set->ops->abort &&
9226+
list_empty(&te->set->pending_update)) {
9227+
list_add_tail(&te->set->pending_update,
9228+
&set_update_list);
9229+
}
91819230
break;
91829231
case NFT_MSG_DELSETELEM:
91839232
te = (struct nft_trans_elem *)trans->data;
@@ -9187,6 +9236,11 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
91879236
if (!nft_setelem_is_catchall(te->set, &te->elem))
91889237
te->set->ndeact--;
91899238

9239+
if (te->set->ops->abort &&
9240+
list_empty(&te->set->pending_update)) {
9241+
list_add_tail(&te->set->pending_update,
9242+
&set_update_list);
9243+
}
91909244
nft_trans_destroy(trans);
91919245
break;
91929246
case NFT_MSG_NEWOBJ:
@@ -9227,6 +9281,8 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
92279281
}
92289282
}
92299283

9284+
nft_set_abort_update(&set_update_list);
9285+
92309286
synchronize_rcu();
92319287

92329288
list_for_each_entry_safe_reverse(trans, next,

net/netfilter/nft_set_pipapo.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,17 +1600,10 @@ static void pipapo_free_fields(struct nft_pipapo_match *m)
16001600
}
16011601
}
16021602

1603-
/**
1604-
* pipapo_reclaim_match - RCU callback to free fields from old matching data
1605-
* @rcu: RCU head
1606-
*/
1607-
static void pipapo_reclaim_match(struct rcu_head *rcu)
1603+
static void pipapo_free_match(struct nft_pipapo_match *m)
16081604
{
1609-
struct nft_pipapo_match *m;
16101605
int i;
16111606

1612-
m = container_of(rcu, struct nft_pipapo_match, rcu);
1613-
16141607
for_each_possible_cpu(i)
16151608
kfree(*per_cpu_ptr(m->scratch, i));
16161609

@@ -1625,7 +1618,19 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
16251618
}
16261619

16271620
/**
1628-
* pipapo_commit() - Replace lookup data with current working copy
1621+
* pipapo_reclaim_match - RCU callback to free fields from old matching data
1622+
* @rcu: RCU head
1623+
*/
1624+
static void pipapo_reclaim_match(struct rcu_head *rcu)
1625+
{
1626+
struct nft_pipapo_match *m;
1627+
1628+
m = container_of(rcu, struct nft_pipapo_match, rcu);
1629+
pipapo_free_match(m);
1630+
}
1631+
1632+
/**
1633+
* nft_pipapo_commit() - Replace lookup data with current working copy
16291634
* @set: nftables API set representation
16301635
*
16311636
* While at it, check if we should perform garbage collection on the working
@@ -1635,7 +1640,7 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
16351640
* We also need to create a new working copy for subsequent insertions and
16361641
* deletions.
16371642
*/
1638-
static void pipapo_commit(const struct nft_set *set)
1643+
static void nft_pipapo_commit(const struct nft_set *set)
16391644
{
16401645
struct nft_pipapo *priv = nft_set_priv(set);
16411646
struct nft_pipapo_match *new_clone, *old;
@@ -1660,15 +1665,34 @@ static void pipapo_commit(const struct nft_set *set)
16601665
priv->clone = new_clone;
16611666
}
16621667

1668+
static void nft_pipapo_abort(const struct nft_set *set)
1669+
{
1670+
struct nft_pipapo *priv = nft_set_priv(set);
1671+
struct nft_pipapo_match *new_clone, *m;
1672+
1673+
if (!priv->dirty)
1674+
return;
1675+
1676+
m = rcu_dereference(priv->match);
1677+
1678+
new_clone = pipapo_clone(m);
1679+
if (IS_ERR(new_clone))
1680+
return;
1681+
1682+
priv->dirty = false;
1683+
1684+
pipapo_free_match(priv->clone);
1685+
priv->clone = new_clone;
1686+
}
1687+
16631688
/**
16641689
* nft_pipapo_activate() - Mark element reference as active given key, commit
16651690
* @net: Network namespace
16661691
* @set: nftables API set representation
16671692
* @elem: nftables API element representation containing key data
16681693
*
16691694
* On insertion, elements are added to a copy of the matching data currently
1670-
* in use for lookups, and not directly inserted into current lookup data, so
1671-
* we'll take care of that by calling pipapo_commit() here. Both
1695+
* in use for lookups, and not directly inserted into current lookup data. Both
16721696
* nft_pipapo_insert() and nft_pipapo_activate() are called once for each
16731697
* element, hence we can't purpose either one as a real commit operation.
16741698
*/
@@ -1684,8 +1708,6 @@ static void nft_pipapo_activate(const struct net *net,
16841708

16851709
nft_set_elem_change_active(net, set, &e->ext);
16861710
nft_set_elem_clear_busy(&e->ext);
1687-
1688-
pipapo_commit(set);
16891711
}
16901712

16911713
/**
@@ -1931,7 +1953,6 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
19311953
if (i == m->field_count) {
19321954
priv->dirty = true;
19331955
pipapo_drop(m, rulemap);
1934-
pipapo_commit(set);
19351956
return;
19361957
}
19371958

@@ -2230,6 +2251,8 @@ const struct nft_set_type nft_set_pipapo_type = {
22302251
.init = nft_pipapo_init,
22312252
.destroy = nft_pipapo_destroy,
22322253
.gc_init = nft_pipapo_gc_init,
2254+
.commit = nft_pipapo_commit,
2255+
.abort = nft_pipapo_abort,
22332256
.elemsize = offsetof(struct nft_pipapo_elem, ext),
22342257
},
22352258
};
@@ -2252,6 +2275,8 @@ const struct nft_set_type nft_set_pipapo_avx2_type = {
22522275
.init = nft_pipapo_init,
22532276
.destroy = nft_pipapo_destroy,
22542277
.gc_init = nft_pipapo_gc_init,
2278+
.commit = nft_pipapo_commit,
2279+
.abort = nft_pipapo_abort,
22552280
.elemsize = offsetof(struct nft_pipapo_elem, ext),
22562281
},
22572282
};

0 commit comments

Comments
 (0)