1/* 2 * Copyright (c) 2009 Patrick McHardy <kaber@trash.net> 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 * Development of this code funded by Astaro AG (http://www.astaro.com/) 9 */ 10 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/list.h> 14#include <linux/rbtree.h> 15#include <linux/netlink.h> 16#include <linux/netfilter.h> 17#include <linux/netfilter/nf_tables.h> 18#include <net/netfilter/nf_tables.h> 19#include <net/netfilter/nf_tables_core.h> 20 21struct nft_lookup { 22 struct nft_set *set; 23 enum nft_registers sreg:8; 24 enum nft_registers dreg:8; 25 struct nft_set_binding binding; 26}; 27 28static void nft_lookup_eval(const struct nft_expr *expr, 29 struct nft_regs *regs, 30 const struct nft_pktinfo *pkt) 31{ 32 const struct nft_lookup *priv = nft_expr_priv(expr); 33 const struct nft_set *set = priv->set; 34 const struct nft_set_ext *ext; 35 36 if (set->ops->lookup(set, ®s->data[priv->sreg], &ext)) { 37 if (set->flags & NFT_SET_MAP) 38 nft_data_copy(®s->data[priv->dreg], 39 nft_set_ext_data(ext), set->dlen); 40 return; 41 } 42 regs->verdict.code = NFT_BREAK; 43} 44 45static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { 46 [NFTA_LOOKUP_SET] = { .type = NLA_STRING }, 47 [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, 48 [NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, 49 [NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, 50}; 51 52static int nft_lookup_init(const struct nft_ctx *ctx, 53 const struct nft_expr *expr, 54 const struct nlattr * const tb[]) 55{ 56 struct nft_lookup *priv = nft_expr_priv(expr); 57 struct nft_set *set; 58 int err; 59 60 if (tb[NFTA_LOOKUP_SET] == NULL || 61 tb[NFTA_LOOKUP_SREG] == NULL) 62 return -EINVAL; 63 64 set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]); 65 if (IS_ERR(set)) { 66 if (tb[NFTA_LOOKUP_SET_ID]) { 67 set = nf_tables_set_lookup_byid(ctx->net, 68 tb[NFTA_LOOKUP_SET_ID]); 69 } 70 if (IS_ERR(set)) 71 return PTR_ERR(set); 72 } 73 74 if (set->flags & NFT_SET_EVAL) 75 return -EOPNOTSUPP; 76 77 priv->sreg = nft_parse_register(tb[NFTA_LOOKUP_SREG]); 78 err = nft_validate_register_load(priv->sreg, set->klen); 79 if (err < 0) 80 return err; 81 82 if (tb[NFTA_LOOKUP_DREG] != NULL) { 83 if (!(set->flags & NFT_SET_MAP)) 84 return -EINVAL; 85 86 priv->dreg = nft_parse_register(tb[NFTA_LOOKUP_DREG]); 87 err = nft_validate_register_store(ctx, priv->dreg, NULL, 88 set->dtype, set->dlen); 89 if (err < 0) 90 return err; 91 } else if (set->flags & NFT_SET_MAP) 92 return -EINVAL; 93 94 priv->binding.flags = set->flags & NFT_SET_MAP; 95 96 err = nf_tables_bind_set(ctx, set, &priv->binding); 97 if (err < 0) 98 return err; 99 100 priv->set = set; 101 return 0; 102} 103 104static void nft_lookup_destroy(const struct nft_ctx *ctx, 105 const struct nft_expr *expr) 106{ 107 struct nft_lookup *priv = nft_expr_priv(expr); 108 109 nf_tables_unbind_set(ctx, priv->set, &priv->binding); 110} 111 112static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) 113{ 114 const struct nft_lookup *priv = nft_expr_priv(expr); 115 116 if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name)) 117 goto nla_put_failure; 118 if (nft_dump_register(skb, NFTA_LOOKUP_SREG, priv->sreg)) 119 goto nla_put_failure; 120 if (priv->set->flags & NFT_SET_MAP) 121 if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) 122 goto nla_put_failure; 123 return 0; 124 125nla_put_failure: 126 return -1; 127} 128 129static struct nft_expr_type nft_lookup_type; 130static const struct nft_expr_ops nft_lookup_ops = { 131 .type = &nft_lookup_type, 132 .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)), 133 .eval = nft_lookup_eval, 134 .init = nft_lookup_init, 135 .destroy = nft_lookup_destroy, 136 .dump = nft_lookup_dump, 137}; 138 139static struct nft_expr_type nft_lookup_type __read_mostly = { 140 .name = "lookup", 141 .ops = &nft_lookup_ops, 142 .policy = nft_lookup_policy, 143 .maxattr = NFTA_LOOKUP_MAX, 144 .owner = THIS_MODULE, 145}; 146 147int __init nft_lookup_module_init(void) 148{ 149 return nft_register_expr(&nft_lookup_type); 150} 151 152void nft_lookup_module_exit(void) 153{ 154 nft_unregister_expr(&nft_lookup_type); 155} 156