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>
24 struct nft_set_binding binding
;
27 #ifdef CONFIG_MITIGATION_RETPOLINE
28 bool nft_set_do_lookup(const struct net
*net
, const struct nft_set
*set
,
29 const u32
*key
, const struct nft_set_ext
**ext
)
31 if (set
->ops
== &nft_set_hash_fast_type
.ops
)
32 return nft_hash_lookup_fast(net
, set
, key
, ext
);
33 if (set
->ops
== &nft_set_hash_type
.ops
)
34 return nft_hash_lookup(net
, set
, key
, ext
);
36 if (set
->ops
== &nft_set_rhash_type
.ops
)
37 return nft_rhash_lookup(net
, set
, key
, ext
);
39 if (set
->ops
== &nft_set_bitmap_type
.ops
)
40 return nft_bitmap_lookup(net
, set
, key
, ext
);
42 if (set
->ops
== &nft_set_pipapo_type
.ops
)
43 return nft_pipapo_lookup(net
, set
, key
, ext
);
44 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
45 if (set
->ops
== &nft_set_pipapo_avx2_type
.ops
)
46 return nft_pipapo_avx2_lookup(net
, set
, key
, ext
);
49 if (set
->ops
== &nft_set_rbtree_type
.ops
)
50 return nft_rbtree_lookup(net
, set
, key
, ext
);
53 return set
->ops
->lookup(net
, set
, key
, ext
);
55 EXPORT_SYMBOL_GPL(nft_set_do_lookup
);
58 void nft_lookup_eval(const struct nft_expr
*expr
,
59 struct nft_regs
*regs
,
60 const struct nft_pktinfo
*pkt
)
62 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
63 const struct nft_set
*set
= priv
->set
;
64 const struct nft_set_ext
*ext
= NULL
;
65 const struct net
*net
= nft_net(pkt
);
68 found
= nft_set_do_lookup(net
, set
, ®s
->data
[priv
->sreg
], &ext
) ^
71 ext
= nft_set_catchall_lookup(net
, set
);
73 regs
->verdict
.code
= NFT_BREAK
;
80 nft_data_copy(®s
->data
[priv
->dreg
],
81 nft_set_ext_data(ext
), set
->dlen
);
83 nft_set_elem_update_expr(ext
, regs
, pkt
);
87 static const struct nla_policy nft_lookup_policy
[NFTA_LOOKUP_MAX
+ 1] = {
88 [NFTA_LOOKUP_SET
] = { .type
= NLA_STRING
,
89 .len
= NFT_SET_MAXNAMELEN
- 1 },
90 [NFTA_LOOKUP_SET_ID
] = { .type
= NLA_U32
},
91 [NFTA_LOOKUP_SREG
] = { .type
= NLA_U32
},
92 [NFTA_LOOKUP_DREG
] = { .type
= NLA_U32
},
94 NLA_POLICY_MASK(NLA_BE32
, NFT_LOOKUP_F_INV
),
97 static int nft_lookup_init(const struct nft_ctx
*ctx
,
98 const struct nft_expr
*expr
,
99 const struct nlattr
* const tb
[])
101 struct nft_lookup
*priv
= nft_expr_priv(expr
);
102 u8 genmask
= nft_genmask_next(ctx
->net
);
107 if (tb
[NFTA_LOOKUP_SET
] == NULL
||
108 tb
[NFTA_LOOKUP_SREG
] == NULL
)
111 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
, tb
[NFTA_LOOKUP_SET
],
112 tb
[NFTA_LOOKUP_SET_ID
], genmask
);
116 err
= nft_parse_register_load(ctx
, tb
[NFTA_LOOKUP_SREG
], &priv
->sreg
,
121 if (tb
[NFTA_LOOKUP_FLAGS
]) {
122 flags
= ntohl(nla_get_be32(tb
[NFTA_LOOKUP_FLAGS
]));
124 if (flags
& NFT_LOOKUP_F_INV
)
128 if (tb
[NFTA_LOOKUP_DREG
] != NULL
) {
131 if (!(set
->flags
& NFT_SET_MAP
))
134 err
= nft_parse_register_store(ctx
, tb
[NFTA_LOOKUP_DREG
],
136 nft_set_datatype(set
),
140 priv
->dreg_set
= true;
141 } else if (set
->flags
& NFT_SET_MAP
) {
142 /* Map given, but user asks for lookup only (i.e. to
143 * ignore value assoicated with key).
145 * This makes no sense for anonymous maps since they are
146 * scoped to the rule, but for named sets this can be useful.
148 if (set
->flags
& NFT_SET_ANONYMOUS
)
152 priv
->binding
.flags
= set
->flags
& NFT_SET_MAP
;
154 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
162 static void nft_lookup_deactivate(const struct nft_ctx
*ctx
,
163 const struct nft_expr
*expr
,
164 enum nft_trans_phase phase
)
166 struct nft_lookup
*priv
= nft_expr_priv(expr
);
168 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
171 static void nft_lookup_activate(const struct nft_ctx
*ctx
,
172 const struct nft_expr
*expr
)
174 struct nft_lookup
*priv
= nft_expr_priv(expr
);
176 nf_tables_activate_set(ctx
, priv
->set
);
179 static void nft_lookup_destroy(const struct nft_ctx
*ctx
,
180 const struct nft_expr
*expr
)
182 struct nft_lookup
*priv
= nft_expr_priv(expr
);
184 nf_tables_destroy_set(ctx
, priv
->set
);
187 static int nft_lookup_dump(struct sk_buff
*skb
,
188 const struct nft_expr
*expr
, bool reset
)
190 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
191 u32 flags
= priv
->invert
? NFT_LOOKUP_F_INV
: 0;
193 if (nla_put_string(skb
, NFTA_LOOKUP_SET
, priv
->set
->name
))
194 goto nla_put_failure
;
195 if (nft_dump_register(skb
, NFTA_LOOKUP_SREG
, priv
->sreg
))
196 goto nla_put_failure
;
198 if (nft_dump_register(skb
, NFTA_LOOKUP_DREG
, priv
->dreg
))
199 goto nla_put_failure
;
200 if (nla_put_be32(skb
, NFTA_LOOKUP_FLAGS
, htonl(flags
)))
201 goto nla_put_failure
;
208 static int nft_lookup_validate(const struct nft_ctx
*ctx
,
209 const struct nft_expr
*expr
)
211 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
212 struct nft_set_iter iter
;
214 if (!(priv
->set
->flags
& NFT_SET_MAP
) ||
215 priv
->set
->dtype
!= NFT_DATA_VERDICT
)
218 iter
.genmask
= nft_genmask_next(ctx
->net
);
219 iter
.type
= NFT_ITER_UPDATE
;
223 iter
.fn
= nft_setelem_validate
;
225 priv
->set
->ops
->walk(ctx
, priv
->set
, &iter
);
227 iter
.err
= nft_set_catchall_validate(ctx
, priv
->set
);
235 static bool nft_lookup_reduce(struct nft_regs_track
*track
,
236 const struct nft_expr
*expr
)
238 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
240 if (priv
->set
->flags
& NFT_SET_MAP
)
241 nft_reg_track_cancel(track
, priv
->dreg
, priv
->set
->dlen
);
246 static const struct nft_expr_ops nft_lookup_ops
= {
247 .type
= &nft_lookup_type
,
248 .size
= NFT_EXPR_SIZE(sizeof(struct nft_lookup
)),
249 .eval
= nft_lookup_eval
,
250 .init
= nft_lookup_init
,
251 .activate
= nft_lookup_activate
,
252 .deactivate
= nft_lookup_deactivate
,
253 .destroy
= nft_lookup_destroy
,
254 .dump
= nft_lookup_dump
,
255 .validate
= nft_lookup_validate
,
256 .reduce
= nft_lookup_reduce
,
259 struct nft_expr_type nft_lookup_type __read_mostly
= {
261 .ops
= &nft_lookup_ops
,
262 .policy
= nft_lookup_policy
,
263 .maxattr
= NFTA_LOOKUP_MAX
,
264 .owner
= THIS_MODULE
,