Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.19-rc2 375 lines 9.9 kB view raw
1/* 2 * Copyright (c) 2016 Laura Garcia <nevola@gmail.com> 3 * 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. 7 * 8 */ 9 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> 19 20struct nft_jhash { 21 enum nft_registers sreg:8; 22 enum nft_registers dreg:8; 23 u8 len; 24 bool autogen_seed:1; 25 u32 modulus; 26 u32 seed; 27 u32 offset; 28 struct nft_set *map; 29}; 30 31static void nft_jhash_eval(const struct nft_expr *expr, 32 struct nft_regs *regs, 33 const struct nft_pktinfo *pkt) 34{ 35 struct nft_jhash *priv = nft_expr_priv(expr); 36 const void *data = &regs->data[priv->sreg]; 37 u32 h; 38 39 h = reciprocal_scale(jhash(data, priv->len, priv->seed), 40 priv->modulus); 41 42 regs->data[priv->dreg] = h + priv->offset; 43} 44 45static void nft_jhash_map_eval(const struct nft_expr *expr, 46 struct nft_regs *regs, 47 const struct nft_pktinfo *pkt) 48{ 49 struct nft_jhash *priv = nft_expr_priv(expr); 50 const void *data = &regs->data[priv->sreg]; 51 const struct nft_set *map = priv->map; 52 const struct nft_set_ext *ext; 53 u32 result; 54 bool found; 55 56 result = reciprocal_scale(jhash(data, priv->len, priv->seed), 57 priv->modulus) + priv->offset; 58 59 found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 60 if (!found) 61 return; 62 63 nft_data_copy(&regs->data[priv->dreg], 64 nft_set_ext_data(ext), map->dlen); 65} 66 67struct nft_symhash { 68 enum nft_registers dreg:8; 69 u32 modulus; 70 u32 offset; 71 struct nft_set *map; 72}; 73 74static void nft_symhash_eval(const struct nft_expr *expr, 75 struct nft_regs *regs, 76 const struct nft_pktinfo *pkt) 77{ 78 struct nft_symhash *priv = nft_expr_priv(expr); 79 struct sk_buff *skb = pkt->skb; 80 u32 h; 81 82 h = reciprocal_scale(__skb_get_hash_symmetric(skb), priv->modulus); 83 84 regs->data[priv->dreg] = h + priv->offset; 85} 86 87static void nft_symhash_map_eval(const struct nft_expr *expr, 88 struct nft_regs *regs, 89 const struct nft_pktinfo *pkt) 90{ 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; 95 u32 result; 96 bool found; 97 98 result = reciprocal_scale(__skb_get_hash_symmetric(skb), 99 priv->modulus) + priv->offset; 100 101 found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 102 if (!found) 103 return; 104 105 nft_data_copy(&regs->data[priv->dreg], 106 nft_set_ext_data(ext), map->dlen); 107} 108 109static 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 }, 120}; 121 122static int nft_jhash_init(const struct nft_ctx *ctx, 123 const struct nft_expr *expr, 124 const struct nlattr * const tb[]) 125{ 126 struct nft_jhash *priv = nft_expr_priv(expr); 127 u32 len; 128 int err; 129 130 if (!tb[NFTA_HASH_SREG] || 131 !tb[NFTA_HASH_DREG] || 132 !tb[NFTA_HASH_LEN] || 133 !tb[NFTA_HASH_MODULUS]) 134 return -EINVAL; 135 136 if (tb[NFTA_HASH_OFFSET]) 137 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET])); 138 139 priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]); 140 priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]); 141 142 err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len); 143 if (err < 0) 144 return err; 145 if (len == 0) 146 return -ERANGE; 147 148 priv->len = len; 149 150 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS])); 151 if (priv->modulus < 1) 152 return -ERANGE; 153 154 if (priv->offset + priv->modulus - 1 < priv->offset) 155 return -EOVERFLOW; 156 157 if (tb[NFTA_HASH_SEED]) { 158 priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED])); 159 } else { 160 priv->autogen_seed = true; 161 get_random_bytes(&priv->seed, sizeof(priv->seed)); 162 } 163 164 return nft_validate_register_load(priv->sreg, len) && 165 nft_validate_register_store(ctx, priv->dreg, NULL, 166 NFT_DATA_VALUE, sizeof(u32)); 167} 168 169static int nft_jhash_map_init(const struct nft_ctx *ctx, 170 const struct nft_expr *expr, 171 const struct nlattr * const tb[]) 172{ 173 struct nft_jhash *priv = nft_expr_priv(expr); 174 u8 genmask = nft_genmask_next(ctx->net); 175 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); 181} 182 183static int nft_symhash_init(const struct nft_ctx *ctx, 184 const struct nft_expr *expr, 185 const struct nlattr * const tb[]) 186{ 187 struct nft_symhash *priv = nft_expr_priv(expr); 188 189 if (!tb[NFTA_HASH_DREG] || 190 !tb[NFTA_HASH_MODULUS]) 191 return -EINVAL; 192 193 if (tb[NFTA_HASH_OFFSET]) 194 priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET])); 195 196 priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]); 197 198 priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS])); 199 if (priv->modulus <= 1) 200 return -ERANGE; 201 202 if (priv->offset + priv->modulus - 1 < priv->offset) 203 return -EOVERFLOW; 204 205 return nft_validate_register_store(ctx, priv->dreg, NULL, 206 NFT_DATA_VALUE, sizeof(u32)); 207} 208 209static int nft_symhash_map_init(const struct nft_ctx *ctx, 210 const struct nft_expr *expr, 211 const struct nlattr * const tb[]) 212{ 213 struct nft_jhash *priv = nft_expr_priv(expr); 214 u8 genmask = nft_genmask_next(ctx->net); 215 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); 221} 222 223static int nft_jhash_dump(struct sk_buff *skb, 224 const struct nft_expr *expr) 225{ 226 const struct nft_jhash *priv = nft_expr_priv(expr); 227 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; 244 return 0; 245 246nla_put_failure: 247 return -1; 248} 249 250static int nft_jhash_map_dump(struct sk_buff *skb, 251 const struct nft_expr *expr) 252{ 253 const struct nft_jhash *priv = nft_expr_priv(expr); 254 255 if (nft_jhash_dump(skb, expr) || 256 nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name)) 257 return -1; 258 259 return 0; 260} 261 262static int nft_symhash_dump(struct sk_buff *skb, 263 const struct nft_expr *expr) 264{ 265 const struct nft_symhash *priv = nft_expr_priv(expr); 266 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; 276 return 0; 277 278nla_put_failure: 279 return -1; 280} 281 282static int nft_symhash_map_dump(struct sk_buff *skb, 283 const struct nft_expr *expr) 284{ 285 const struct nft_symhash *priv = nft_expr_priv(expr); 286 287 if (nft_symhash_dump(skb, expr) || 288 nla_put_string(skb, NFTA_HASH_SET_NAME, priv->map->name)) 289 return -1; 290 291 return 0; 292} 293 294static struct nft_expr_type nft_hash_type; 295static 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, 301}; 302 303static 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, 309}; 310 311static 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, 317}; 318 319static 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, 325}; 326 327static const struct nft_expr_ops * 328nft_hash_select_ops(const struct nft_ctx *ctx, 329 const struct nlattr * const tb[]) 330{ 331 u32 type; 332 333 if (!tb[NFTA_HASH_TYPE]) 334 return &nft_jhash_ops; 335 336 type = ntohl(nla_get_be32(tb[NFTA_HASH_TYPE])); 337 switch (type) { 338 case NFT_HASH_SYM: 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; 346 default: 347 break; 348 } 349 return ERR_PTR(-EOPNOTSUPP); 350} 351 352static struct nft_expr_type nft_hash_type __read_mostly = { 353 .name = "hash", 354 .select_ops = nft_hash_select_ops, 355 .policy = nft_hash_policy, 356 .maxattr = NFTA_HASH_MAX, 357 .owner = THIS_MODULE, 358}; 359 360static int __init nft_hash_module_init(void) 361{ 362 return nft_register_expr(&nft_hash_type); 363} 364 365static void __exit nft_hash_module_exit(void) 366{ 367 nft_unregister_expr(&nft_hash_type); 368} 369 370module_init(nft_hash_module_init); 371module_exit(nft_hash_module_exit); 372 373MODULE_LICENSE("GPL"); 374MODULE_AUTHOR("Laura Garcia <nevola@gmail.com>"); 375MODULE_ALIAS_NFT_EXPR("hash");