2 * Copyright (c) 2016 Laura Garcia <nevola@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/netlink.h>
14 #include <linux/netfilter.h>
15 #include <linux/netfilter/nf_tables.h>
16 #include <net/netfilter/nf_tables.h>
17 #include <net/netfilter/nf_tables_core.h>
18 #include <linux/jhash.h>
21 enum nft_registers sreg
:8;
22 enum nft_registers dreg
:8;
31 static void nft_jhash_eval(const struct nft_expr
*expr
,
32 struct nft_regs
*regs
,
33 const struct nft_pktinfo
*pkt
)
35 struct nft_jhash
*priv
= nft_expr_priv(expr
);
36 const void *data
= ®s
->data
[priv
->sreg
];
39 h
= reciprocal_scale(jhash(data
, priv
->len
, priv
->seed
),
42 regs
->data
[priv
->dreg
] = h
+ priv
->offset
;
45 static void nft_jhash_map_eval(const struct nft_expr
*expr
,
46 struct nft_regs
*regs
,
47 const struct nft_pktinfo
*pkt
)
49 struct nft_jhash
*priv
= nft_expr_priv(expr
);
50 const void *data
= ®s
->data
[priv
->sreg
];
51 const struct nft_set
*map
= priv
->map
;
52 const struct nft_set_ext
*ext
;
56 result
= reciprocal_scale(jhash(data
, priv
->len
, priv
->seed
),
57 priv
->modulus
) + priv
->offset
;
59 found
= map
->ops
->lookup(nft_net(pkt
), map
, &result
, &ext
);
63 nft_data_copy(®s
->data
[priv
->dreg
],
64 nft_set_ext_data(ext
), map
->dlen
);
68 enum nft_registers dreg
:8;
74 static void nft_symhash_eval(const struct nft_expr
*expr
,
75 struct nft_regs
*regs
,
76 const struct nft_pktinfo
*pkt
)
78 struct nft_symhash
*priv
= nft_expr_priv(expr
);
79 struct sk_buff
*skb
= pkt
->skb
;
82 h
= reciprocal_scale(__skb_get_hash_symmetric(skb
), priv
->modulus
);
84 regs
->data
[priv
->dreg
] = h
+ priv
->offset
;
87 static void nft_symhash_map_eval(const struct nft_expr
*expr
,
88 struct nft_regs
*regs
,
89 const struct nft_pktinfo
*pkt
)
91 struct nft_symhash
*priv
= nft_expr_priv(expr
);
92 struct sk_buff
*skb
= pkt
->skb
;
93 const struct nft_set
*map
= priv
->map
;
94 const struct nft_set_ext
*ext
;
98 result
= reciprocal_scale(__skb_get_hash_symmetric(skb
),
99 priv
->modulus
) + priv
->offset
;
101 found
= map
->ops
->lookup(nft_net(pkt
), map
, &result
, &ext
);
105 nft_data_copy(®s
->data
[priv
->dreg
],
106 nft_set_ext_data(ext
), map
->dlen
);
109 static const struct nla_policy nft_hash_policy
[NFTA_HASH_MAX
+ 1] = {
110 [NFTA_HASH_SREG
] = { .type
= NLA_U32
},
111 [NFTA_HASH_DREG
] = { .type
= NLA_U32
},
112 [NFTA_HASH_LEN
] = { .type
= NLA_U32
},
113 [NFTA_HASH_MODULUS
] = { .type
= NLA_U32
},
114 [NFTA_HASH_SEED
] = { .type
= NLA_U32
},
115 [NFTA_HASH_OFFSET
] = { .type
= NLA_U32
},
116 [NFTA_HASH_TYPE
] = { .type
= NLA_U32
},
117 [NFTA_HASH_SET_NAME
] = { .type
= NLA_STRING
,
118 .len
= NFT_SET_MAXNAMELEN
- 1 },
119 [NFTA_HASH_SET_ID
] = { .type
= NLA_U32
},
122 static int nft_jhash_init(const struct nft_ctx
*ctx
,
123 const struct nft_expr
*expr
,
124 const struct nlattr
* const tb
[])
126 struct nft_jhash
*priv
= nft_expr_priv(expr
);
130 if (!tb
[NFTA_HASH_SREG
] ||
131 !tb
[NFTA_HASH_DREG
] ||
132 !tb
[NFTA_HASH_LEN
] ||
133 !tb
[NFTA_HASH_MODULUS
])
136 if (tb
[NFTA_HASH_OFFSET
])
137 priv
->offset
= ntohl(nla_get_be32(tb
[NFTA_HASH_OFFSET
]));
139 priv
->sreg
= nft_parse_register(tb
[NFTA_HASH_SREG
]);
140 priv
->dreg
= nft_parse_register(tb
[NFTA_HASH_DREG
]);
142 err
= nft_parse_u32_check(tb
[NFTA_HASH_LEN
], U8_MAX
, &len
);
150 priv
->modulus
= ntohl(nla_get_be32(tb
[NFTA_HASH_MODULUS
]));
151 if (priv
->modulus
< 1)
154 if (priv
->offset
+ priv
->modulus
- 1 < priv
->offset
)
157 if (tb
[NFTA_HASH_SEED
]) {
158 priv
->seed
= ntohl(nla_get_be32(tb
[NFTA_HASH_SEED
]));
160 priv
->autogen_seed
= true;
161 get_random_bytes(&priv
->seed
, sizeof(priv
->seed
));
164 return nft_validate_register_load(priv
->sreg
, len
) &&
165 nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
166 NFT_DATA_VALUE
, sizeof(u32
));
169 static int nft_jhash_map_init(const struct nft_ctx
*ctx
,
170 const struct nft_expr
*expr
,
171 const struct nlattr
* const tb
[])
173 struct nft_jhash
*priv
= nft_expr_priv(expr
);
174 u8 genmask
= nft_genmask_next(ctx
->net
);
176 nft_jhash_init(ctx
, expr
, tb
);
177 priv
->map
= nft_set_lookup_global(ctx
->net
, ctx
->table
,
178 tb
[NFTA_HASH_SET_NAME
],
179 tb
[NFTA_HASH_SET_ID
], genmask
);
180 return PTR_ERR_OR_ZERO(priv
->map
);
183 static int nft_symhash_init(const struct nft_ctx
*ctx
,
184 const struct nft_expr
*expr
,
185 const struct nlattr
* const tb
[])
187 struct nft_symhash
*priv
= nft_expr_priv(expr
);
189 if (!tb
[NFTA_HASH_DREG
] ||
190 !tb
[NFTA_HASH_MODULUS
])
193 if (tb
[NFTA_HASH_OFFSET
])
194 priv
->offset
= ntohl(nla_get_be32(tb
[NFTA_HASH_OFFSET
]));
196 priv
->dreg
= nft_parse_register(tb
[NFTA_HASH_DREG
]);
198 priv
->modulus
= ntohl(nla_get_be32(tb
[NFTA_HASH_MODULUS
]));
199 if (priv
->modulus
<= 1)
202 if (priv
->offset
+ priv
->modulus
- 1 < priv
->offset
)
205 return nft_validate_register_store(ctx
, priv
->dreg
, NULL
,
206 NFT_DATA_VALUE
, sizeof(u32
));
209 static int nft_symhash_map_init(const struct nft_ctx
*ctx
,
210 const struct nft_expr
*expr
,
211 const struct nlattr
* const tb
[])
213 struct nft_jhash
*priv
= nft_expr_priv(expr
);
214 u8 genmask
= nft_genmask_next(ctx
->net
);
216 nft_symhash_init(ctx
, expr
, tb
);
217 priv
->map
= nft_set_lookup_global(ctx
->net
, ctx
->table
,
218 tb
[NFTA_HASH_SET_NAME
],
219 tb
[NFTA_HASH_SET_ID
], genmask
);
220 return PTR_ERR_OR_ZERO(priv
->map
);
223 static int nft_jhash_dump(struct sk_buff
*skb
,
224 const struct nft_expr
*expr
)
226 const struct nft_jhash
*priv
= nft_expr_priv(expr
);
228 if (nft_dump_register(skb
, NFTA_HASH_SREG
, priv
->sreg
))
229 goto nla_put_failure
;
230 if (nft_dump_register(skb
, NFTA_HASH_DREG
, priv
->dreg
))
231 goto nla_put_failure
;
232 if (nla_put_be32(skb
, NFTA_HASH_LEN
, htonl(priv
->len
)))
233 goto nla_put_failure
;
234 if (nla_put_be32(skb
, NFTA_HASH_MODULUS
, htonl(priv
->modulus
)))
235 goto nla_put_failure
;
236 if (!priv
->autogen_seed
&&
237 nla_put_be32(skb
, NFTA_HASH_SEED
, htonl(priv
->seed
)))
238 goto nla_put_failure
;
239 if (priv
->offset
!= 0)
240 if (nla_put_be32(skb
, NFTA_HASH_OFFSET
, htonl(priv
->offset
)))
241 goto nla_put_failure
;
242 if (nla_put_be32(skb
, NFTA_HASH_TYPE
, htonl(NFT_HASH_JENKINS
)))
243 goto nla_put_failure
;
250 static int nft_jhash_map_dump(struct sk_buff
*skb
,
251 const struct nft_expr
*expr
)
253 const struct nft_jhash
*priv
= nft_expr_priv(expr
);
255 if (nft_jhash_dump(skb
, expr
) ||
256 nla_put_string(skb
, NFTA_HASH_SET_NAME
, priv
->map
->name
))
262 static int nft_symhash_dump(struct sk_buff
*skb
,
263 const struct nft_expr
*expr
)
265 const struct nft_symhash
*priv
= nft_expr_priv(expr
);
267 if (nft_dump_register(skb
, NFTA_HASH_DREG
, priv
->dreg
))
268 goto nla_put_failure
;
269 if (nla_put_be32(skb
, NFTA_HASH_MODULUS
, htonl(priv
->modulus
)))
270 goto nla_put_failure
;
271 if (priv
->offset
!= 0)
272 if (nla_put_be32(skb
, NFTA_HASH_OFFSET
, htonl(priv
->offset
)))
273 goto nla_put_failure
;
274 if (nla_put_be32(skb
, NFTA_HASH_TYPE
, htonl(NFT_HASH_SYM
)))
275 goto nla_put_failure
;
282 static int nft_symhash_map_dump(struct sk_buff
*skb
,
283 const struct nft_expr
*expr
)
285 const struct nft_symhash
*priv
= nft_expr_priv(expr
);
287 if (nft_symhash_dump(skb
, expr
) ||
288 nla_put_string(skb
, NFTA_HASH_SET_NAME
, priv
->map
->name
))
294 static struct nft_expr_type nft_hash_type
;
295 static const struct nft_expr_ops nft_jhash_ops
= {
296 .type
= &nft_hash_type
,
297 .size
= NFT_EXPR_SIZE(sizeof(struct nft_jhash
)),
298 .eval
= nft_jhash_eval
,
299 .init
= nft_jhash_init
,
300 .dump
= nft_jhash_dump
,
303 static const struct nft_expr_ops nft_jhash_map_ops
= {
304 .type
= &nft_hash_type
,
305 .size
= NFT_EXPR_SIZE(sizeof(struct nft_jhash
)),
306 .eval
= nft_jhash_map_eval
,
307 .init
= nft_jhash_map_init
,
308 .dump
= nft_jhash_map_dump
,
311 static const struct nft_expr_ops nft_symhash_ops
= {
312 .type
= &nft_hash_type
,
313 .size
= NFT_EXPR_SIZE(sizeof(struct nft_symhash
)),
314 .eval
= nft_symhash_eval
,
315 .init
= nft_symhash_init
,
316 .dump
= nft_symhash_dump
,
319 static const struct nft_expr_ops nft_symhash_map_ops
= {
320 .type
= &nft_hash_type
,
321 .size
= NFT_EXPR_SIZE(sizeof(struct nft_symhash
)),
322 .eval
= nft_symhash_map_eval
,
323 .init
= nft_symhash_map_init
,
324 .dump
= nft_symhash_map_dump
,
327 static const struct nft_expr_ops
*
328 nft_hash_select_ops(const struct nft_ctx
*ctx
,
329 const struct nlattr
* const tb
[])
333 if (!tb
[NFTA_HASH_TYPE
])
334 return &nft_jhash_ops
;
336 type
= ntohl(nla_get_be32(tb
[NFTA_HASH_TYPE
]));
339 if (tb
[NFTA_HASH_SET_NAME
])
340 return &nft_symhash_map_ops
;
341 return &nft_symhash_ops
;
342 case NFT_HASH_JENKINS
:
343 if (tb
[NFTA_HASH_SET_NAME
])
344 return &nft_jhash_map_ops
;
345 return &nft_jhash_ops
;
349 return ERR_PTR(-EOPNOTSUPP
);
352 static struct nft_expr_type nft_hash_type __read_mostly
= {
354 .select_ops
= nft_hash_select_ops
,
355 .policy
= nft_hash_policy
,
356 .maxattr
= NFTA_HASH_MAX
,
357 .owner
= THIS_MODULE
,
360 static int __init
nft_hash_module_init(void)
362 return nft_register_expr(&nft_hash_type
);
365 static void __exit
nft_hash_module_exit(void)
367 nft_unregister_expr(&nft_hash_type
);
370 module_init(nft_hash_module_init
);
371 module_exit(nft_hash_module_exit
);
373 MODULE_LICENSE("GPL");
374 MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>");
375 MODULE_ALIAS_NFT_EXPR("hash");