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

netfilter: nft_numgen: add map lookups for numgen statements

This patch includes a new attribute in the numgen structure to allow
the lookup of an element based on the number generator as a key.

For this purpose, different ops have been included to extend the
current numgen inc functions.

Currently, only supported for numgen incremental operations, but
it will be supported for random in a follow-up patch.

Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Laura Garcia Liebana and committed by
Pablo Neira Ayuso
d734a288 8b2ebb6c

+84 -5
+4
include/uapi/linux/netfilter/nf_tables.h
··· 1450 1450 * @NFTA_NG_MODULUS: maximum counter value (NLA_U32) 1451 1451 * @NFTA_NG_TYPE: operation type (NLA_U32) 1452 1452 * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32) 1453 + * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING) 1454 + * @NFTA_NG_SET_ID: id of the map (NLA_U32) 1453 1455 */ 1454 1456 enum nft_ng_attributes { 1455 1457 NFTA_NG_UNSPEC, ··· 1459 1457 NFTA_NG_MODULUS, 1460 1458 NFTA_NG_TYPE, 1461 1459 NFTA_NG_OFFSET, 1460 + NFTA_NG_SET_NAME, 1461 + NFTA_NG_SET_ID, 1462 1462 __NFTA_NG_MAX 1463 1463 }; 1464 1464 #define NFTA_NG_MAX (__NFTA_NG_MAX - 1)
+80 -5
net/netfilter/nft_numgen.c
··· 24 24 u32 modulus; 25 25 atomic_t counter; 26 26 u32 offset; 27 + struct nft_set *map; 27 28 }; 28 29 29 - static void nft_ng_inc_eval(const struct nft_expr *expr, 30 - struct nft_regs *regs, 31 - const struct nft_pktinfo *pkt) 30 + static u32 nft_ng_inc_gen(struct nft_ng_inc *priv) 32 31 { 33 - struct nft_ng_inc *priv = nft_expr_priv(expr); 34 32 u32 nval, oval; 35 33 36 34 do { ··· 36 38 nval = (oval + 1 < priv->modulus) ? oval + 1 : 0; 37 39 } while (atomic_cmpxchg(&priv->counter, oval, nval) != oval); 38 40 39 - regs->data[priv->dreg] = nval + priv->offset; 41 + return nval + priv->offset; 42 + } 43 + 44 + static void nft_ng_inc_eval(const struct nft_expr *expr, 45 + struct nft_regs *regs, 46 + const struct nft_pktinfo *pkt) 47 + { 48 + struct nft_ng_inc *priv = nft_expr_priv(expr); 49 + 50 + regs->data[priv->dreg] = nft_ng_inc_gen(priv); 51 + } 52 + 53 + static void nft_ng_inc_map_eval(const struct nft_expr *expr, 54 + struct nft_regs *regs, 55 + const struct nft_pktinfo *pkt) 56 + { 57 + struct nft_ng_inc *priv = nft_expr_priv(expr); 58 + const struct nft_set *map = priv->map; 59 + const struct nft_set_ext *ext; 60 + u32 result; 61 + bool found; 62 + 63 + result = nft_ng_inc_gen(priv); 64 + found = map->ops->lookup(nft_net(pkt), map, &result, &ext); 65 + 66 + if (!found) 67 + return; 68 + 69 + nft_data_copy(&regs->data[priv->dreg], 70 + nft_set_ext_data(ext), map->dlen); 40 71 } 41 72 42 73 static const struct nla_policy nft_ng_policy[NFTA_NG_MAX + 1] = { ··· 73 46 [NFTA_NG_MODULUS] = { .type = NLA_U32 }, 74 47 [NFTA_NG_TYPE] = { .type = NLA_U32 }, 75 48 [NFTA_NG_OFFSET] = { .type = NLA_U32 }, 49 + [NFTA_NG_SET_NAME] = { .type = NLA_STRING, 50 + .len = NFT_SET_MAXNAMELEN - 1 }, 51 + [NFTA_NG_SET_ID] = { .type = NLA_U32 }, 76 52 }; 77 53 78 54 static int nft_ng_inc_init(const struct nft_ctx *ctx, ··· 99 69 100 70 return nft_validate_register_store(ctx, priv->dreg, NULL, 101 71 NFT_DATA_VALUE, sizeof(u32)); 72 + } 73 + 74 + static int nft_ng_inc_map_init(const struct nft_ctx *ctx, 75 + const struct nft_expr *expr, 76 + const struct nlattr * const tb[]) 77 + { 78 + struct nft_ng_inc *priv = nft_expr_priv(expr); 79 + u8 genmask = nft_genmask_next(ctx->net); 80 + 81 + nft_ng_inc_init(ctx, expr, tb); 82 + 83 + priv->map = nft_set_lookup_global(ctx->net, ctx->table, 84 + tb[NFTA_NG_SET_NAME], 85 + tb[NFTA_NG_SET_ID], genmask); 86 + 87 + if (IS_ERR(priv->map)) 88 + return PTR_ERR(priv->map); 89 + 90 + return 0; 102 91 } 103 92 104 93 static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg, ··· 144 95 145 96 return nft_ng_dump(skb, priv->dreg, priv->modulus, NFT_NG_INCREMENTAL, 146 97 priv->offset); 98 + } 99 + 100 + static int nft_ng_inc_map_dump(struct sk_buff *skb, 101 + const struct nft_expr *expr) 102 + { 103 + const struct nft_ng_inc *priv = nft_expr_priv(expr); 104 + 105 + if (nft_ng_dump(skb, priv->dreg, priv->modulus, 106 + NFT_NG_INCREMENTAL, priv->offset) || 107 + nla_put_string(skb, NFTA_NG_SET_NAME, priv->map->name)) 108 + goto nla_put_failure; 109 + 110 + return 0; 111 + 112 + nla_put_failure: 113 + return -1; 147 114 } 148 115 149 116 struct nft_ng_random { ··· 221 156 .dump = nft_ng_inc_dump, 222 157 }; 223 158 159 + static const struct nft_expr_ops nft_ng_inc_map_ops = { 160 + .type = &nft_ng_type, 161 + .size = NFT_EXPR_SIZE(sizeof(struct nft_ng_inc)), 162 + .eval = nft_ng_inc_map_eval, 163 + .init = nft_ng_inc_map_init, 164 + .dump = nft_ng_inc_map_dump, 165 + }; 166 + 224 167 static const struct nft_expr_ops nft_ng_random_ops = { 225 168 .type = &nft_ng_type, 226 169 .size = NFT_EXPR_SIZE(sizeof(struct nft_ng_random)), ··· 251 178 252 179 switch (type) { 253 180 case NFT_NG_INCREMENTAL: 181 + if (tb[NFTA_NG_SET_NAME]) 182 + return &nft_ng_inc_map_ops; 254 183 return &nft_ng_inc_ops; 255 184 case NFT_NG_RANDOM: 256 185 return &nft_ng_random_ops;