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>
20 enum nft_registers sreg
:8;
21 enum nft_registers dreg
:8;
23 struct nft_set_binding binding
;
26 void nft_lookup_eval(const struct nft_expr
*expr
,
27 struct nft_regs
*regs
,
28 const struct nft_pktinfo
*pkt
)
30 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
31 const struct nft_set
*set
= priv
->set
;
32 const struct nft_set_ext
*ext
= NULL
;
35 found
= set
->ops
->lookup(nft_net(pkt
), set
, ®s
->data
[priv
->sreg
],
38 regs
->verdict
.code
= NFT_BREAK
;
43 if (set
->flags
& NFT_SET_MAP
)
44 nft_data_copy(®s
->data
[priv
->dreg
],
45 nft_set_ext_data(ext
), set
->dlen
);
47 nft_set_elem_update_expr(ext
, regs
, pkt
);
51 static const struct nla_policy nft_lookup_policy
[NFTA_LOOKUP_MAX
+ 1] = {
52 [NFTA_LOOKUP_SET
] = { .type
= NLA_STRING
,
53 .len
= NFT_SET_MAXNAMELEN
- 1 },
54 [NFTA_LOOKUP_SET_ID
] = { .type
= NLA_U32
},
55 [NFTA_LOOKUP_SREG
] = { .type
= NLA_U32
},
56 [NFTA_LOOKUP_DREG
] = { .type
= NLA_U32
},
57 [NFTA_LOOKUP_FLAGS
] = { .type
= NLA_U32
},
60 static int nft_lookup_init(const struct nft_ctx
*ctx
,
61 const struct nft_expr
*expr
,
62 const struct nlattr
* const tb
[])
64 struct nft_lookup
*priv
= nft_expr_priv(expr
);
65 u8 genmask
= nft_genmask_next(ctx
->net
);
70 if (tb
[NFTA_LOOKUP_SET
] == NULL
||
71 tb
[NFTA_LOOKUP_SREG
] == NULL
)
74 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
, tb
[NFTA_LOOKUP_SET
],
75 tb
[NFTA_LOOKUP_SET_ID
], genmask
);
79 priv
->sreg
= nft_parse_register(tb
[NFTA_LOOKUP_SREG
]);
80 err
= nft_validate_register_load(priv
->sreg
, set
->klen
);
84 if (tb
[NFTA_LOOKUP_FLAGS
]) {
85 flags
= ntohl(nla_get_be32(tb
[NFTA_LOOKUP_FLAGS
]));
87 if (flags
& ~NFT_LOOKUP_F_INV
)
90 if (flags
& NFT_LOOKUP_F_INV
) {
91 if (set
->flags
& NFT_SET_MAP
)
97 if (tb
[NFTA_LOOKUP_DREG
] != NULL
) {
100 if (!(set
->flags
& NFT_SET_MAP
))
103 priv
->dreg
= nft_parse_register(tb
[NFTA_LOOKUP_DREG
]);
104 err
= nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
105 set
->dtype
, set
->dlen
);
108 } else if (set
->flags
& NFT_SET_MAP
)
111 priv
->binding
.flags
= set
->flags
& NFT_SET_MAP
;
113 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
121 static void nft_lookup_deactivate(const struct nft_ctx
*ctx
,
122 const struct nft_expr
*expr
,
123 enum nft_trans_phase phase
)
125 struct nft_lookup
*priv
= nft_expr_priv(expr
);
127 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
130 static void nft_lookup_activate(const struct nft_ctx
*ctx
,
131 const struct nft_expr
*expr
)
133 struct nft_lookup
*priv
= nft_expr_priv(expr
);
138 static void nft_lookup_destroy(const struct nft_ctx
*ctx
,
139 const struct nft_expr
*expr
)
141 struct nft_lookup
*priv
= nft_expr_priv(expr
);
143 nf_tables_destroy_set(ctx
, priv
->set
);
146 static int nft_lookup_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
148 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
149 u32 flags
= priv
->invert
? NFT_LOOKUP_F_INV
: 0;
151 if (nla_put_string(skb
, NFTA_LOOKUP_SET
, priv
->set
->name
))
152 goto nla_put_failure
;
153 if (nft_dump_register(skb
, NFTA_LOOKUP_SREG
, priv
->sreg
))
154 goto nla_put_failure
;
155 if (priv
->set
->flags
& NFT_SET_MAP
)
156 if (nft_dump_register(skb
, NFTA_LOOKUP_DREG
, priv
->dreg
))
157 goto nla_put_failure
;
158 if (nla_put_be32(skb
, NFTA_LOOKUP_FLAGS
, htonl(flags
)))
159 goto nla_put_failure
;
166 static int nft_lookup_validate_setelem(const struct nft_ctx
*ctx
,
168 const struct nft_set_iter
*iter
,
169 struct nft_set_elem
*elem
)
171 const struct nft_set_ext
*ext
= nft_set_elem_ext(set
, elem
->priv
);
172 struct nft_ctx
*pctx
= (struct nft_ctx
*)ctx
;
173 const struct nft_data
*data
;
176 if (nft_set_ext_exists(ext
, NFT_SET_EXT_FLAGS
) &&
177 *nft_set_ext_flags(ext
) & NFT_SET_ELEM_INTERVAL_END
)
180 data
= nft_set_ext_data(ext
);
181 switch (data
->verdict
.code
) {
185 err
= nft_chain_validate(ctx
, data
->verdict
.chain
);
197 static int nft_lookup_validate(const struct nft_ctx
*ctx
,
198 const struct nft_expr
*expr
,
199 const struct nft_data
**d
)
201 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
202 struct nft_set_iter iter
;
204 if (!(priv
->set
->flags
& NFT_SET_MAP
) ||
205 priv
->set
->dtype
!= NFT_DATA_VERDICT
)
208 iter
.genmask
= nft_genmask_next(ctx
->net
);
212 iter
.fn
= nft_lookup_validate_setelem
;
214 priv
->set
->ops
->walk(ctx
, priv
->set
, &iter
);
221 static const struct nft_expr_ops nft_lookup_ops
= {
222 .type
= &nft_lookup_type
,
223 .size
= NFT_EXPR_SIZE(sizeof(struct nft_lookup
)),
224 .eval
= nft_lookup_eval
,
225 .init
= nft_lookup_init
,
226 .activate
= nft_lookup_activate
,
227 .deactivate
= nft_lookup_deactivate
,
228 .destroy
= nft_lookup_destroy
,
229 .dump
= nft_lookup_dump
,
230 .validate
= nft_lookup_validate
,
233 struct nft_expr_type nft_lookup_type __read_mostly
= {
235 .ops
= &nft_lookup_ops
,
236 .policy
= nft_lookup_policy
,
237 .maxattr
= NFTA_LOOKUP_MAX
,
238 .owner
= THIS_MODULE
,