root/net/netfilter/nft_hash.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_jhash_eval
  2. nft_symhash_eval
  3. nft_jhash_init
  4. nft_symhash_init
  5. nft_jhash_dump
  6. nft_symhash_dump
  7. nft_hash_select_ops
  8. nft_hash_module_init
  9. nft_hash_module_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016 Laura Garcia <nevola@gmail.com>
   4  */
   5 
   6 #include <linux/kernel.h>
   7 #include <linux/init.h>
   8 #include <linux/module.h>
   9 #include <linux/netlink.h>
  10 #include <linux/netfilter.h>
  11 #include <linux/netfilter/nf_tables.h>
  12 #include <net/netfilter/nf_tables.h>
  13 #include <net/netfilter/nf_tables_core.h>
  14 #include <linux/jhash.h>
  15 
  16 struct nft_jhash {
  17         enum nft_registers      sreg:8;
  18         enum nft_registers      dreg:8;
  19         u8                      len;
  20         bool                    autogen_seed:1;
  21         u32                     modulus;
  22         u32                     seed;
  23         u32                     offset;
  24 };
  25 
  26 static void nft_jhash_eval(const struct nft_expr *expr,
  27                            struct nft_regs *regs,
  28                            const struct nft_pktinfo *pkt)
  29 {
  30         struct nft_jhash *priv = nft_expr_priv(expr);
  31         const void *data = &regs->data[priv->sreg];
  32         u32 h;
  33 
  34         h = reciprocal_scale(jhash(data, priv->len, priv->seed),
  35                              priv->modulus);
  36 
  37         regs->data[priv->dreg] = h + priv->offset;
  38 }
  39 
  40 struct nft_symhash {
  41         enum nft_registers      dreg:8;
  42         u32                     modulus;
  43         u32                     offset;
  44 };
  45 
  46 static void nft_symhash_eval(const struct nft_expr *expr,
  47                              struct nft_regs *regs,
  48                              const struct nft_pktinfo *pkt)
  49 {
  50         struct nft_symhash *priv = nft_expr_priv(expr);
  51         struct sk_buff *skb = pkt->skb;
  52         u32 h;
  53 
  54         h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus);
  55 
  56         regs->data[priv->dreg] = h + priv->offset;
  57 }
  58 
  59 static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
  60         [NFTA_HASH_SREG]        = { .type = NLA_U32 },
  61         [NFTA_HASH_DREG]        = { .type = NLA_U32 },
  62         [NFTA_HASH_LEN]         = { .type = NLA_U32 },
  63         [NFTA_HASH_MODULUS]     = { .type = NLA_U32 },
  64         [NFTA_HASH_SEED]        = { .type = NLA_U32 },
  65         [NFTA_HASH_OFFSET]      = { .type = NLA_U32 },
  66         [NFTA_HASH_TYPE]        = { .type = NLA_U32 },
  67 };
  68 
  69 static int nft_jhash_init(const struct nft_ctx *ctx,
  70                           const struct nft_expr *expr,
  71                           const struct nlattr * const tb[])
  72 {
  73         struct nft_jhash *priv = nft_expr_priv(expr);
  74         u32 len;
  75         int err;
  76 
  77         if (!tb[NFTA_HASH_SREG] ||
  78             !tb[NFTA_HASH_DREG] ||
  79             !tb[NFTA_HASH_LEN]  ||
  80             !tb[NFTA_HASH_MODULUS])
  81                 return -EINVAL;
  82 
  83         if (tb[NFTA_HASH_OFFSET])
  84                 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
  85 
  86         priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]);
  87         priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
  88 
  89         err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
  90         if (err < 0)
  91                 return err;
  92         if (len == 0)
  93                 return -ERANGE;
  94 
  95         priv->len = len;
  96 
  97         priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
  98         if (priv->modulus < 1)
  99                 return -ERANGE;
 100 
 101         if (priv->offset + priv->modulus - 1 < priv->offset)
 102                 return -EOVERFLOW;
 103 
 104         if (tb[NFTA_HASH_SEED]) {
 105                 priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
 106         } else {
 107                 priv->autogen_seed = true;
 108                 get_random_bytes(&priv->seed, sizeof(priv->seed));
 109         }
 110 
 111         return nft_validate_register_load(priv->sreg, len) &&
 112                nft_validate_register_store(ctx, priv->dreg, NULL,
 113                                            NFT_DATA_VALUE, sizeof(u32));
 114 }
 115 
 116 static int nft_symhash_init(const struct nft_ctx *ctx,
 117                             const struct nft_expr *expr,
 118                             const struct nlattr * const tb[])
 119 {
 120         struct nft_symhash *priv = nft_expr_priv(expr);
 121 
 122         if (!tb[NFTA_HASH_DREG]    ||
 123             !tb[NFTA_HASH_MODULUS])
 124                 return -EINVAL;
 125 
 126         if (tb[NFTA_HASH_OFFSET])
 127                 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
 128 
 129         priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
 130 
 131         priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
 132         if (priv->modulus < 1)
 133                 return -ERANGE;
 134 
 135         if (priv->offset + priv->modulus - 1 < priv->offset)
 136                 return -EOVERFLOW;
 137 
 138         return nft_validate_register_store(ctx, priv->dreg, NULL,
 139                                            NFT_DATA_VALUE, sizeof(u32));
 140 }
 141 
 142 static int nft_jhash_dump(struct sk_buff *skb,
 143                           const struct nft_expr *expr)
 144 {
 145         const struct nft_jhash *priv = nft_expr_priv(expr);
 146 
 147         if (nft_dump_register(skb, NFTA_HASH_SREG, priv->sreg))
 148                 goto nla_put_failure;
 149         if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
 150                 goto nla_put_failure;
 151         if (nla_put_be32(skb, NFTA_HASH_LEN, htonl(priv->len)))
 152                 goto nla_put_failure;
 153         if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
 154                 goto nla_put_failure;
 155         if (!priv->autogen_seed &&
 156             nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
 157                 goto nla_put_failure;
 158         if (priv->offset != 0)
 159                 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
 160                         goto nla_put_failure;
 161         if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_JENKINS)))
 162                 goto nla_put_failure;
 163         return 0;
 164 
 165 nla_put_failure:
 166         return -1;
 167 }
 168 
 169 static int nft_symhash_dump(struct sk_buff *skb,
 170                             const struct nft_expr *expr)
 171 {
 172         const struct nft_symhash *priv = nft_expr_priv(expr);
 173 
 174         if (nft_dump_register(skb, NFTA_HASH_DREG, priv->dreg))
 175                 goto nla_put_failure;
 176         if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
 177                 goto nla_put_failure;
 178         if (priv->offset != 0)
 179                 if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
 180                         goto nla_put_failure;
 181         if (nla_put_be32(skb, NFTA_HASH_TYPE, htonl(NFT_HASH_SYM)))
 182                 goto nla_put_failure;
 183         return 0;
 184 
 185 nla_put_failure:
 186         return -1;
 187 }
 188 
 189 static struct nft_expr_type nft_hash_type;
 190 static const struct nft_expr_ops nft_jhash_ops = {
 191         .type           = &nft_hash_type,
 192         .size           = NFT_EXPR_SIZE(sizeof(struct nft_jhash)),
 193         .eval           = nft_jhash_eval,
 194         .init           = nft_jhash_init,
 195         .dump           = nft_jhash_dump,
 196 };
 197 
 198 static const struct nft_expr_ops nft_symhash_ops = {
 199         .type           = &nft_hash_type,
 200         .size           = NFT_EXPR_SIZE(sizeof(struct nft_symhash)),
 201         .eval           = nft_symhash_eval,
 202         .init           = nft_symhash_init,
 203         .dump           = nft_symhash_dump,
 204 };
 205 
 206 static const struct nft_expr_ops *
 207 nft_hash_select_ops(const struct nft_ctx *ctx,
 208                     const struct nlattr * const tb[])
 209 {
 210         u32 type;
 211 
 212         if (!tb[NFTA_HASH_TYPE])
 213                 return &nft_jhash_ops;
 214 
 215         type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE]));
 216         switch (type) {
 217         case NFT_HASH_SYM:
 218                 return &nft_symhash_ops;
 219         case NFT_HASH_JENKINS:
 220                 return &nft_jhash_ops;
 221         default:
 222                 break;
 223         }
 224         return ERR_PTR(-EOPNOTSUPP);
 225 }
 226 
 227 static struct nft_expr_type nft_hash_type __read_mostly = {
 228         .name           = "hash",
 229         .select_ops     = nft_hash_select_ops,
 230         .policy         = nft_hash_policy,
 231         .maxattr        = NFTA_HASH_MAX,
 232         .owner          = THIS_MODULE,
 233 };
 234 
 235 static int __init nft_hash_module_init(void)
 236 {
 237         return nft_register_expr(&nft_hash_type);
 238 }
 239 
 240 static void __exit nft_hash_module_exit(void)
 241 {
 242         nft_unregister_expr(&nft_hash_type);
 243 }
 244 
 245 module_init(nft_hash_module_init);
 246 module_exit(nft_hash_module_exit);
 247 
 248 MODULE_LICENSE("GPL");
 249 MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>");
 250 MODULE_ALIAS_NFT_EXPR("hash");

/* [<][>][^][v][top][bottom][index][help] */