Blame view
net/netfilter/nft_hash.c
3.83 KB
cb1b69b0b netfilter: nf_tab... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* * Copyright (c) 2016 Laura Garcia <nevola@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/netlink.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables_core.h> #include <linux/jhash.h> struct nft_hash { enum nft_registers sreg:8; enum nft_registers dreg:8; u8 len; u32 modulus; u32 seed; |
70ca767ea netfilter: nft_ha... |
26 |
u32 offset; |
cb1b69b0b netfilter: nf_tab... |
27 28 29 30 31 32 33 34 |
}; static void nft_hash_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { struct nft_hash *priv = nft_expr_priv(expr); const void *data = ®s->data[priv->sreg]; |
70ca767ea netfilter: nft_ha... |
35 |
u32 h; |
cb1b69b0b netfilter: nf_tab... |
36 |
|
70ca767ea netfilter: nft_ha... |
37 38 |
h = reciprocal_scale(jhash(data, priv->len, priv->seed), priv->modulus); regs->data[priv->dreg] = h + priv->offset; |
cb1b69b0b netfilter: nf_tab... |
39 |
} |
a5e573364 netfilter: nft_ha... |
40 |
static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = { |
cb1b69b0b netfilter: nf_tab... |
41 42 43 44 45 |
[NFTA_HASH_SREG] = { .type = NLA_U32 }, [NFTA_HASH_DREG] = { .type = NLA_U32 }, [NFTA_HASH_LEN] = { .type = NLA_U32 }, [NFTA_HASH_MODULUS] = { .type = NLA_U32 }, [NFTA_HASH_SEED] = { .type = NLA_U32 }, |
5751e175c netfilter: nft_ha... |
46 |
[NFTA_HASH_OFFSET] = { .type = NLA_U32 }, |
cb1b69b0b netfilter: nf_tab... |
47 48 49 50 51 52 53 54 |
}; static int nft_hash_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { struct nft_hash *priv = nft_expr_priv(expr); u32 len; |
abd66e9f3 netfilter: nft_ha... |
55 |
int err; |
cb1b69b0b netfilter: nf_tab... |
56 57 58 59 60 61 62 |
if (!tb[NFTA_HASH_SREG] || !tb[NFTA_HASH_DREG] || !tb[NFTA_HASH_LEN] || !tb[NFTA_HASH_SEED] || !tb[NFTA_HASH_MODULUS]) return -EINVAL; |
70ca767ea netfilter: nft_ha... |
63 64 |
if (tb[NFTA_HASH_OFFSET]) priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET])); |
cb1b69b0b netfilter: nf_tab... |
65 66 |
priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]); priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]); |
abd66e9f3 netfilter: nft_ha... |
67 68 69 70 |
err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len); if (err < 0) return err; if (len == 0) |
cb1b69b0b netfilter: nf_tab... |
71 72 73 74 75 76 77 |
return -ERANGE; priv->len = len; priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS])); if (priv->modulus <= 1) return -ERANGE; |
14e2dee09 netfilter: nft_ha... |
78 |
if (priv->offset + priv->modulus - 1 < priv->offset) |
70ca767ea netfilter: nft_ha... |
79 |
return -EOVERFLOW; |
cb1b69b0b netfilter: nf_tab... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED])); return nft_validate_register_load(priv->sreg, len) && nft_validate_register_store(ctx, priv->dreg, NULL, NFT_DATA_VALUE, sizeof(u32)); } static int nft_hash_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct nft_hash *priv = nft_expr_priv(expr); if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg)) goto nla_put_failure; if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg)) goto nla_put_failure; |
7073b16f3 netfilter: nf_tab... |
96 |
if (nla_put_be32(skb, NFTA_HASH_LEN, htonl(priv->len))) |
cb1b69b0b netfilter: nf_tab... |
97 |
goto nla_put_failure; |
7073b16f3 netfilter: nf_tab... |
98 |
if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus))) |
cb1b69b0b netfilter: nf_tab... |
99 |
goto nla_put_failure; |
7073b16f3 netfilter: nf_tab... |
100 |
if (nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed))) |
cb1b69b0b netfilter: nf_tab... |
101 |
goto nla_put_failure; |
70ca767ea netfilter: nft_ha... |
102 103 104 |
if (priv->offset != 0) if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset))) goto nla_put_failure; |
cb1b69b0b netfilter: nf_tab... |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
return 0; nla_put_failure: return -1; } static struct nft_expr_type nft_hash_type; static const struct nft_expr_ops nft_hash_ops = { .type = &nft_hash_type, .size = NFT_EXPR_SIZE(sizeof(struct nft_hash)), .eval = nft_hash_eval, .init = nft_hash_init, .dump = nft_hash_dump, }; static struct nft_expr_type nft_hash_type __read_mostly = { .name = "hash", .ops = &nft_hash_ops, .policy = nft_hash_policy, .maxattr = NFTA_HASH_MAX, .owner = THIS_MODULE, }; static int __init nft_hash_module_init(void) { return nft_register_expr(&nft_hash_type); } static void __exit nft_hash_module_exit(void) { nft_unregister_expr(&nft_hash_type); } module_init(nft_hash_module_init); module_exit(nft_hash_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>"); MODULE_ALIAS_NFT_EXPR("hash"); |