1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/list.h>
11 #include <linux/rbtree.h>
12 #include <linux/netlink.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nf_tables.h>
15 #include <net/netfilter/nf_tables.h>
16 #include <net/netfilter/nf_tables_core.h>
23 struct nft_set_binding binding
;
26 #ifdef CONFIG_RETPOLINE
27 bool nft_set_do_lookup(const struct net
*net
, const struct nft_set
*set
,
28 const u32
*key
, const struct nft_set_ext
**ext
)
30 if (set
->ops
== &nft_set_hash_fast_type
.ops
)
31 return nft_hash_lookup_fast(net
, set
, key
, ext
);
32 if (set
->ops
== &nft_set_hash_type
.ops
)
33 return nft_hash_lookup(net
, set
, key
, ext
);
35 if (set
->ops
== &nft_set_rhash_type
.ops
)
36 return nft_rhash_lookup(net
, set
, key
, ext
);
38 if (set
->ops
== &nft_set_bitmap_type
.ops
)
39 return nft_bitmap_lookup(net
, set
, key
, ext
);
41 if (set
->ops
== &nft_set_pipapo_type
.ops
)
42 return nft_pipapo_lookup(net
, set
, key
, ext
);
43 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
44 if (set
->ops
== &nft_set_pipapo_avx2_type
.ops
)
45 return nft_pipapo_avx2_lookup(net
, set
, key
, ext
);
48 if (set
->ops
== &nft_set_rbtree_type
.ops
)
49 return nft_rbtree_lookup(net
, set
, key
, ext
);
52 return set
->ops
->lookup(net
, set
, key
, ext
);
54 EXPORT_SYMBOL_GPL(nft_set_do_lookup
);
57 void nft_lookup_eval(const struct nft_expr
*expr
,
58 struct nft_regs
*regs
,
59 const struct nft_pktinfo
*pkt
)
61 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
62 const struct nft_set
*set
= priv
->set
;
63 const struct nft_set_ext
*ext
= NULL
;
64 const struct net
*net
= nft_net(pkt
);
67 found
= nft_set_do_lookup(net
, set
, ®s
->data
[priv
->sreg
], &ext
) ^
70 ext
= nft_set_catchall_lookup(net
, set
);
72 regs
->verdict
.code
= NFT_BREAK
;
78 if (set
->flags
& NFT_SET_MAP
)
79 nft_data_copy(®s
->data
[priv
->dreg
],
80 nft_set_ext_data(ext
), set
->dlen
);
82 nft_set_elem_update_expr(ext
, regs
, pkt
);
86 static const struct nla_policy nft_lookup_policy
[NFTA_LOOKUP_MAX
+ 1] = {
87 [NFTA_LOOKUP_SET
] = { .type
= NLA_STRING
,
88 .len
= NFT_SET_MAXNAMELEN
- 1 },
89 [NFTA_LOOKUP_SET_ID
] = { .type
= NLA_U32
},
90 [NFTA_LOOKUP_SREG
] = { .type
= NLA_U32
},
91 [NFTA_LOOKUP_DREG
] = { .type
= NLA_U32
},
92 [NFTA_LOOKUP_FLAGS
] = { .type
= NLA_U32
},
95 static int nft_lookup_init(const struct nft_ctx
*ctx
,
96 const struct nft_expr
*expr
,
97 const struct nlattr
* const tb
[])
99 struct nft_lookup
*priv
= nft_expr_priv(expr
);
100 u8 genmask
= nft_genmask_next(ctx
->net
);
105 if (tb
[NFTA_LOOKUP_SET
] == NULL
||
106 tb
[NFTA_LOOKUP_SREG
] == NULL
)
109 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
, tb
[NFTA_LOOKUP_SET
],
110 tb
[NFTA_LOOKUP_SET_ID
], genmask
);
114 err
= nft_parse_register_load(tb
[NFTA_LOOKUP_SREG
], &priv
->sreg
,
119 if (tb
[NFTA_LOOKUP_FLAGS
]) {
120 flags
= ntohl(nla_get_be32(tb
[NFTA_LOOKUP_FLAGS
]));
122 if (flags
& ~NFT_LOOKUP_F_INV
)
125 if (flags
& NFT_LOOKUP_F_INV
) {
126 if (set
->flags
& NFT_SET_MAP
)
132 if (tb
[NFTA_LOOKUP_DREG
] != NULL
) {
135 if (!(set
->flags
& NFT_SET_MAP
))
138 err
= nft_parse_register_store(ctx
, tb
[NFTA_LOOKUP_DREG
],
139 &priv
->dreg
, NULL
, set
->dtype
,
143 } else if (set
->flags
& NFT_SET_MAP
)
146 priv
->binding
.flags
= set
->flags
& NFT_SET_MAP
;
148 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
156 static void nft_lookup_deactivate(const struct nft_ctx
*ctx
,
157 const struct nft_expr
*expr
,
158 enum nft_trans_phase phase
)
160 struct nft_lookup
*priv
= nft_expr_priv(expr
);
162 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
165 static void nft_lookup_activate(const struct nft_ctx
*ctx
,
166 const struct nft_expr
*expr
)
168 struct nft_lookup
*priv
= nft_expr_priv(expr
);
170 nf_tables_activate_set(ctx
, priv
->set
);
173 static void nft_lookup_destroy(const struct nft_ctx
*ctx
,
174 const struct nft_expr
*expr
)
176 struct nft_lookup
*priv
= nft_expr_priv(expr
);
178 nf_tables_destroy_set(ctx
, priv
->set
);
181 static int nft_lookup_dump(struct sk_buff
*skb
,
182 const struct nft_expr
*expr
, bool reset
)
184 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
185 u32 flags
= priv
->invert
? NFT_LOOKUP_F_INV
: 0;
187 if (nla_put_string(skb
, NFTA_LOOKUP_SET
, priv
->set
->name
))
188 goto nla_put_failure
;
189 if (nft_dump_register(skb
, NFTA_LOOKUP_SREG
, priv
->sreg
))
190 goto nla_put_failure
;
191 if (priv
->set
->flags
& NFT_SET_MAP
)
192 if (nft_dump_register(skb
, NFTA_LOOKUP_DREG
, priv
->dreg
))
193 goto nla_put_failure
;
194 if (nla_put_be32(skb
, NFTA_LOOKUP_FLAGS
, htonl(flags
)))
195 goto nla_put_failure
;
202 static int nft_lookup_validate(const struct nft_ctx
*ctx
,
203 const struct nft_expr
*expr
,
204 const struct nft_data
**d
)
206 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
207 struct nft_set_iter iter
;
209 if (!(priv
->set
->flags
& NFT_SET_MAP
) ||
210 priv
->set
->dtype
!= NFT_DATA_VERDICT
)
213 iter
.genmask
= nft_genmask_next(ctx
->net
);
217 iter
.fn
= nft_setelem_validate
;
219 priv
->set
->ops
->walk(ctx
, priv
->set
, &iter
);
221 iter
.err
= nft_set_catchall_validate(ctx
, priv
->set
);
229 static bool nft_lookup_reduce(struct nft_regs_track
*track
,
230 const struct nft_expr
*expr
)
232 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
234 if (priv
->set
->flags
& NFT_SET_MAP
)
235 nft_reg_track_cancel(track
, priv
->dreg
, priv
->set
->dlen
);
240 static const struct nft_expr_ops nft_lookup_ops
= {
241 .type
= &nft_lookup_type
,
242 .size
= NFT_EXPR_SIZE(sizeof(struct nft_lookup
)),
243 .eval
= nft_lookup_eval
,
244 .init
= nft_lookup_init
,
245 .activate
= nft_lookup_activate
,
246 .deactivate
= nft_lookup_deactivate
,
247 .destroy
= nft_lookup_destroy
,
248 .dump
= nft_lookup_dump
,
249 .validate
= nft_lookup_validate
,
250 .reduce
= nft_lookup_reduce
,
253 struct nft_expr_type nft_lookup_type __read_mostly
= {
255 .ops
= &nft_lookup_ops
,
256 .policy
= nft_lookup_policy
,
257 .maxattr
= NFTA_LOOKUP_MAX
,
258 .owner
= THIS_MODULE
,