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
;
35 found
= set
->ops
->lookup(nft_net(pkt
), set
, ®s
->data
[priv
->sreg
],
38 regs
->verdict
.code
= NFT_BREAK
;
42 if (set
->flags
& NFT_SET_MAP
)
43 nft_data_copy(®s
->data
[priv
->dreg
],
44 nft_set_ext_data(ext
), set
->dlen
);
46 nft_set_elem_update_expr(ext
, regs
, pkt
);
49 static const struct nla_policy nft_lookup_policy
[NFTA_LOOKUP_MAX
+ 1] = {
50 [NFTA_LOOKUP_SET
] = { .type
= NLA_STRING
,
51 .len
= NFT_SET_MAXNAMELEN
- 1 },
52 [NFTA_LOOKUP_SET_ID
] = { .type
= NLA_U32
},
53 [NFTA_LOOKUP_SREG
] = { .type
= NLA_U32
},
54 [NFTA_LOOKUP_DREG
] = { .type
= NLA_U32
},
55 [NFTA_LOOKUP_FLAGS
] = { .type
= NLA_U32
},
58 static int nft_lookup_init(const struct nft_ctx
*ctx
,
59 const struct nft_expr
*expr
,
60 const struct nlattr
* const tb
[])
62 struct nft_lookup
*priv
= nft_expr_priv(expr
);
63 u8 genmask
= nft_genmask_next(ctx
->net
);
68 if (tb
[NFTA_LOOKUP_SET
] == NULL
||
69 tb
[NFTA_LOOKUP_SREG
] == NULL
)
72 set
= nft_set_lookup_global(ctx
->net
, ctx
->table
, tb
[NFTA_LOOKUP_SET
],
73 tb
[NFTA_LOOKUP_SET_ID
], genmask
);
77 priv
->sreg
= nft_parse_register(tb
[NFTA_LOOKUP_SREG
]);
78 err
= nft_validate_register_load(priv
->sreg
, set
->klen
);
82 if (tb
[NFTA_LOOKUP_FLAGS
]) {
83 flags
= ntohl(nla_get_be32(tb
[NFTA_LOOKUP_FLAGS
]));
85 if (flags
& ~NFT_LOOKUP_F_INV
)
88 if (flags
& NFT_LOOKUP_F_INV
) {
89 if (set
->flags
& NFT_SET_MAP
)
95 if (tb
[NFTA_LOOKUP_DREG
] != NULL
) {
98 if (!(set
->flags
& NFT_SET_MAP
))
101 priv
->dreg
= nft_parse_register(tb
[NFTA_LOOKUP_DREG
]);
102 err
= nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
103 set
->dtype
, set
->dlen
);
106 } else if (set
->flags
& NFT_SET_MAP
)
109 priv
->binding
.flags
= set
->flags
& NFT_SET_MAP
;
111 err
= nf_tables_bind_set(ctx
, set
, &priv
->binding
);
119 static void nft_lookup_deactivate(const struct nft_ctx
*ctx
,
120 const struct nft_expr
*expr
,
121 enum nft_trans_phase phase
)
123 struct nft_lookup
*priv
= nft_expr_priv(expr
);
125 nf_tables_deactivate_set(ctx
, priv
->set
, &priv
->binding
, phase
);
128 static void nft_lookup_activate(const struct nft_ctx
*ctx
,
129 const struct nft_expr
*expr
)
131 struct nft_lookup
*priv
= nft_expr_priv(expr
);
136 static void nft_lookup_destroy(const struct nft_ctx
*ctx
,
137 const struct nft_expr
*expr
)
139 struct nft_lookup
*priv
= nft_expr_priv(expr
);
141 nf_tables_destroy_set(ctx
, priv
->set
);
144 static int nft_lookup_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
146 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
147 u32 flags
= priv
->invert
? NFT_LOOKUP_F_INV
: 0;
149 if (nla_put_string(skb
, NFTA_LOOKUP_SET
, priv
->set
->name
))
150 goto nla_put_failure
;
151 if (nft_dump_register(skb
, NFTA_LOOKUP_SREG
, priv
->sreg
))
152 goto nla_put_failure
;
153 if (priv
->set
->flags
& NFT_SET_MAP
)
154 if (nft_dump_register(skb
, NFTA_LOOKUP_DREG
, priv
->dreg
))
155 goto nla_put_failure
;
156 if (nla_put_be32(skb
, NFTA_LOOKUP_FLAGS
, htonl(flags
)))
157 goto nla_put_failure
;
164 static int nft_lookup_validate_setelem(const struct nft_ctx
*ctx
,
166 const struct nft_set_iter
*iter
,
167 struct nft_set_elem
*elem
)
169 const struct nft_set_ext
*ext
= nft_set_elem_ext(set
, elem
->priv
);
170 struct nft_ctx
*pctx
= (struct nft_ctx
*)ctx
;
171 const struct nft_data
*data
;
174 if (nft_set_ext_exists(ext
, NFT_SET_EXT_FLAGS
) &&
175 *nft_set_ext_flags(ext
) & NFT_SET_ELEM_INTERVAL_END
)
178 data
= nft_set_ext_data(ext
);
179 switch (data
->verdict
.code
) {
183 err
= nft_chain_validate(ctx
, data
->verdict
.chain
);
195 static int nft_lookup_validate(const struct nft_ctx
*ctx
,
196 const struct nft_expr
*expr
,
197 const struct nft_data
**d
)
199 const struct nft_lookup
*priv
= nft_expr_priv(expr
);
200 struct nft_set_iter iter
;
202 if (!(priv
->set
->flags
& NFT_SET_MAP
) ||
203 priv
->set
->dtype
!= NFT_DATA_VERDICT
)
206 iter
.genmask
= nft_genmask_next(ctx
->net
);
210 iter
.fn
= nft_lookup_validate_setelem
;
212 priv
->set
->ops
->walk(ctx
, priv
->set
, &iter
);
219 static const struct nft_expr_ops nft_lookup_ops
= {
220 .type
= &nft_lookup_type
,
221 .size
= NFT_EXPR_SIZE(sizeof(struct nft_lookup
)),
222 .eval
= nft_lookup_eval
,
223 .init
= nft_lookup_init
,
224 .activate
= nft_lookup_activate
,
225 .deactivate
= nft_lookup_deactivate
,
226 .destroy
= nft_lookup_destroy
,
227 .dump
= nft_lookup_dump
,
228 .validate
= nft_lookup_validate
,
231 struct nft_expr_type nft_lookup_type __read_mostly
= {
233 .ops
= &nft_lookup_ops
,
234 .policy
= nft_lookup_policy
,
235 .maxattr
= NFTA_LOOKUP_MAX
,
236 .owner
= THIS_MODULE
,