netfilter: nf_tables: add select_ops for stateful objects
This patch adds support for overloading stateful objects operations through the select_ops() callback, just as it is implemented for expressions. This change is needed for upcoming additions to the stateful objects infrastructure. Signed-off-by: Pablo M. Bermudo Garay <pablombg@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
bea74641e3
commit
dfc46034b5
6 changed files with 90 additions and 46 deletions
|
@ -1007,12 +1007,12 @@ int nft_verdict_dump(struct sk_buff *skb, int type,
|
|||
*
|
||||
* @list: table stateful object list node
|
||||
* @table: table this object belongs to
|
||||
* @type: pointer to object type
|
||||
* @data: pointer to object data
|
||||
* @name: name of this stateful object
|
||||
* @genmask: generation mask
|
||||
* @use: number of references to this stateful object
|
||||
* @data: object data, layout depends on type
|
||||
* @ops: object operations
|
||||
* @data: pointer to object data
|
||||
*/
|
||||
struct nft_object {
|
||||
struct list_head list;
|
||||
|
@ -1021,7 +1021,7 @@ struct nft_object {
|
|||
u32 genmask:2,
|
||||
use:30;
|
||||
/* runtime data below here */
|
||||
const struct nft_object_type *type ____cacheline_aligned;
|
||||
const struct nft_object_ops *ops ____cacheline_aligned;
|
||||
unsigned char data[]
|
||||
__attribute__((aligned(__alignof__(u64))));
|
||||
};
|
||||
|
@ -1044,27 +1044,39 @@ void nft_obj_notify(struct net *net, struct nft_table *table,
|
|||
/**
|
||||
* struct nft_object_type - stateful object type
|
||||
*
|
||||
* @eval: stateful object evaluation function
|
||||
* @select_ops: function to select nft_object_ops
|
||||
* @ops: default ops, used when no select_ops functions is present
|
||||
* @list: list node in list of object types
|
||||
* @type: stateful object numeric type
|
||||
* @size: stateful object size
|
||||
* @owner: module owner
|
||||
* @maxattr: maximum netlink attribute
|
||||
* @policy: netlink attribute policy
|
||||
*/
|
||||
struct nft_object_type {
|
||||
const struct nft_object_ops *(*select_ops)(const struct nft_ctx *,
|
||||
const struct nlattr * const tb[]);
|
||||
const struct nft_object_ops *ops;
|
||||
struct list_head list;
|
||||
u32 type;
|
||||
unsigned int maxattr;
|
||||
struct module *owner;
|
||||
const struct nla_policy *policy;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nft_object_ops - stateful object operations
|
||||
*
|
||||
* @eval: stateful object evaluation function
|
||||
* @size: stateful object size
|
||||
* @init: initialize object from netlink attributes
|
||||
* @destroy: release existing stateful object
|
||||
* @dump: netlink dump stateful object
|
||||
*/
|
||||
struct nft_object_type {
|
||||
struct nft_object_ops {
|
||||
void (*eval)(struct nft_object *obj,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt);
|
||||
struct list_head list;
|
||||
u32 type;
|
||||
unsigned int size;
|
||||
unsigned int maxattr;
|
||||
struct module *owner;
|
||||
const struct nla_policy *policy;
|
||||
int (*init)(const struct nft_ctx *ctx,
|
||||
const struct nlattr *const tb[],
|
||||
struct nft_object *obj);
|
||||
|
@ -1072,6 +1084,7 @@ struct nft_object_type {
|
|||
int (*dump)(struct sk_buff *skb,
|
||||
struct nft_object *obj,
|
||||
bool reset);
|
||||
const struct nft_object_type *type;
|
||||
};
|
||||
|
||||
int nft_register_obj(struct nft_object_type *obj_type);
|
||||
|
|
|
@ -4248,7 +4248,7 @@ struct nft_object *nf_tables_obj_lookup(const struct nft_table *table,
|
|||
|
||||
list_for_each_entry(obj, &table->objects, list) {
|
||||
if (!nla_strcmp(nla, obj->name) &&
|
||||
objtype == obj->type->type &&
|
||||
objtype == obj->ops->type->type &&
|
||||
nft_active_genmask(obj, genmask))
|
||||
return obj;
|
||||
}
|
||||
|
@ -4270,6 +4270,7 @@ static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
|
|||
const struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *tb[type->maxattr + 1];
|
||||
const struct nft_object_ops *ops;
|
||||
struct nft_object *obj;
|
||||
int err;
|
||||
|
||||
|
@ -4282,16 +4283,27 @@ static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
|
|||
memset(tb, 0, sizeof(tb[0]) * (type->maxattr + 1));
|
||||
}
|
||||
|
||||
if (type->select_ops) {
|
||||
ops = type->select_ops(ctx, (const struct nlattr * const *)tb);
|
||||
if (IS_ERR(ops)) {
|
||||
err = PTR_ERR(ops);
|
||||
goto err1;
|
||||
}
|
||||
} else {
|
||||
ops = type->ops;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
obj = kzalloc(sizeof(struct nft_object) + type->size, GFP_KERNEL);
|
||||
obj = kzalloc(sizeof(*obj) + ops->size, GFP_KERNEL);
|
||||
if (obj == NULL)
|
||||
goto err1;
|
||||
|
||||
err = type->init(ctx, (const struct nlattr * const *)tb, obj);
|
||||
err = ops->init(ctx, (const struct nlattr * const *)tb, obj);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
obj->type = type;
|
||||
obj->ops = ops;
|
||||
|
||||
return obj;
|
||||
err2:
|
||||
kfree(obj);
|
||||
|
@ -4307,7 +4319,7 @@ static int nft_object_dump(struct sk_buff *skb, unsigned int attr,
|
|||
nest = nla_nest_start(skb, attr);
|
||||
if (!nest)
|
||||
goto nla_put_failure;
|
||||
if (obj->type->dump(skb, obj, reset) < 0)
|
||||
if (obj->ops->dump(skb, obj, reset) < 0)
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(skb, nest);
|
||||
return 0;
|
||||
|
@ -4418,8 +4430,8 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
|
|||
err3:
|
||||
kfree(obj->name);
|
||||
err2:
|
||||
if (obj->type->destroy)
|
||||
obj->type->destroy(obj);
|
||||
if (obj->ops->destroy)
|
||||
obj->ops->destroy(obj);
|
||||
kfree(obj);
|
||||
err1:
|
||||
module_put(type->owner);
|
||||
|
@ -4446,7 +4458,7 @@ static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
|
|||
|
||||
if (nla_put_string(skb, NFTA_OBJ_TABLE, table->name) ||
|
||||
nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
|
||||
nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->type->type)) ||
|
||||
nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
|
||||
nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
|
||||
nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
|
||||
goto nla_put_failure;
|
||||
|
@ -4500,7 +4512,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
goto cont;
|
||||
if (filter &&
|
||||
filter->type != NFT_OBJECT_UNSPEC &&
|
||||
obj->type->type != filter->type)
|
||||
obj->ops->type->type != filter->type)
|
||||
goto cont;
|
||||
|
||||
if (nf_tables_fill_obj_info(skb, net, NETLINK_CB(cb->skb).portid,
|
||||
|
@ -4628,10 +4640,10 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
|
|||
|
||||
static void nft_obj_destroy(struct nft_object *obj)
|
||||
{
|
||||
if (obj->type->destroy)
|
||||
obj->type->destroy(obj);
|
||||
if (obj->ops->destroy)
|
||||
obj->ops->destroy(obj);
|
||||
|
||||
module_put(obj->type->owner);
|
||||
module_put(obj->ops->type->owner);
|
||||
kfree(obj->name);
|
||||
kfree(obj);
|
||||
}
|
||||
|
|
|
@ -175,15 +175,21 @@ static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
|
|||
[NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_counter_obj __read_mostly = {
|
||||
.type = NFT_OBJECT_COUNTER,
|
||||
static struct nft_object_type nft_counter_obj_type;
|
||||
static const struct nft_object_ops nft_counter_obj_ops = {
|
||||
.type = &nft_counter_obj_type,
|
||||
.size = sizeof(struct nft_counter_percpu_priv),
|
||||
.maxattr = NFTA_COUNTER_MAX,
|
||||
.policy = nft_counter_policy,
|
||||
.eval = nft_counter_obj_eval,
|
||||
.init = nft_counter_obj_init,
|
||||
.destroy = nft_counter_obj_destroy,
|
||||
.dump = nft_counter_obj_dump,
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_counter_obj_type __read_mostly = {
|
||||
.type = NFT_OBJECT_COUNTER,
|
||||
.ops = &nft_counter_obj_ops,
|
||||
.maxattr = NFTA_COUNTER_MAX,
|
||||
.policy = nft_counter_policy,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -271,7 +277,7 @@ static int __init nft_counter_module_init(void)
|
|||
for_each_possible_cpu(cpu)
|
||||
seqcount_init(per_cpu_ptr(&nft_counter_seq, cpu));
|
||||
|
||||
err = nft_register_obj(&nft_counter_obj);
|
||||
err = nft_register_obj(&nft_counter_obj_type);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -281,14 +287,14 @@ static int __init nft_counter_module_init(void)
|
|||
|
||||
return 0;
|
||||
err1:
|
||||
nft_unregister_obj(&nft_counter_obj);
|
||||
nft_unregister_obj(&nft_counter_obj_type);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit nft_counter_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_counter_type);
|
||||
nft_unregister_obj(&nft_counter_obj);
|
||||
nft_unregister_obj(&nft_counter_obj_type);
|
||||
}
|
||||
|
||||
module_init(nft_counter_module_init);
|
||||
|
|
|
@ -904,15 +904,21 @@ static const struct nla_policy nft_ct_helper_policy[NFTA_CT_HELPER_MAX + 1] = {
|
|||
[NFTA_CT_HELPER_L4PROTO] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_ct_helper_obj __read_mostly = {
|
||||
.type = NFT_OBJECT_CT_HELPER,
|
||||
static struct nft_object_type nft_ct_helper_obj_type;
|
||||
static const struct nft_object_ops nft_ct_helper_obj_ops = {
|
||||
.type = &nft_ct_helper_obj_type,
|
||||
.size = sizeof(struct nft_ct_helper_obj),
|
||||
.maxattr = NFTA_CT_HELPER_MAX,
|
||||
.policy = nft_ct_helper_policy,
|
||||
.eval = nft_ct_helper_obj_eval,
|
||||
.init = nft_ct_helper_obj_init,
|
||||
.destroy = nft_ct_helper_obj_destroy,
|
||||
.dump = nft_ct_helper_obj_dump,
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_ct_helper_obj_type __read_mostly = {
|
||||
.type = NFT_OBJECT_CT_HELPER,
|
||||
.ops = &nft_ct_helper_obj_ops,
|
||||
.maxattr = NFTA_CT_HELPER_MAX,
|
||||
.policy = nft_ct_helper_policy,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -930,7 +936,7 @@ static int __init nft_ct_module_init(void)
|
|||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
err = nft_register_obj(&nft_ct_helper_obj);
|
||||
err = nft_register_obj(&nft_ct_helper_obj_type);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
|
@ -945,7 +951,7 @@ static int __init nft_ct_module_init(void)
|
|||
|
||||
static void __exit nft_ct_module_exit(void)
|
||||
{
|
||||
nft_unregister_obj(&nft_ct_helper_obj);
|
||||
nft_unregister_obj(&nft_ct_helper_obj_type);
|
||||
nft_unregister_expr(&nft_notrack_type);
|
||||
nft_unregister_expr(&nft_ct_type);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ static void nft_objref_eval(const struct nft_expr *expr,
|
|||
{
|
||||
struct nft_object *obj = nft_objref_priv(expr);
|
||||
|
||||
obj->type->eval(obj, regs, pkt);
|
||||
obj->ops->eval(obj, regs, pkt);
|
||||
}
|
||||
|
||||
static int nft_objref_init(const struct nft_ctx *ctx,
|
||||
|
@ -54,7 +54,8 @@ static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
|||
const struct nft_object *obj = nft_objref_priv(expr);
|
||||
|
||||
if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->name) ||
|
||||
nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE, htonl(obj->type->type)))
|
||||
nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
|
||||
htonl(obj->ops->type->type)))
|
||||
goto nla_put_failure;
|
||||
|
||||
return 0;
|
||||
|
@ -104,7 +105,7 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
|
|||
return;
|
||||
}
|
||||
obj = *nft_set_ext_obj(ext);
|
||||
obj->type->eval(obj, regs, pkt);
|
||||
obj->ops->eval(obj, regs, pkt);
|
||||
}
|
||||
|
||||
static int nft_objref_map_init(const struct nft_ctx *ctx,
|
||||
|
|
|
@ -151,14 +151,20 @@ static int nft_quota_obj_dump(struct sk_buff *skb, struct nft_object *obj,
|
|||
return nft_quota_do_dump(skb, priv, reset);
|
||||
}
|
||||
|
||||
static struct nft_object_type nft_quota_obj __read_mostly = {
|
||||
.type = NFT_OBJECT_QUOTA,
|
||||
static struct nft_object_type nft_quota_obj_type;
|
||||
static const struct nft_object_ops nft_quota_obj_ops = {
|
||||
.type = &nft_quota_obj_type,
|
||||
.size = sizeof(struct nft_quota),
|
||||
.maxattr = NFTA_QUOTA_MAX,
|
||||
.policy = nft_quota_policy,
|
||||
.init = nft_quota_obj_init,
|
||||
.eval = nft_quota_obj_eval,
|
||||
.dump = nft_quota_obj_dump,
|
||||
};
|
||||
|
||||
static struct nft_object_type nft_quota_obj_type __read_mostly = {
|
||||
.type = NFT_OBJECT_QUOTA,
|
||||
.ops = &nft_quota_obj_ops,
|
||||
.maxattr = NFTA_QUOTA_MAX,
|
||||
.policy = nft_quota_policy,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -209,7 +215,7 @@ static int __init nft_quota_module_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = nft_register_obj(&nft_quota_obj);
|
||||
err = nft_register_obj(&nft_quota_obj_type);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -219,14 +225,14 @@ static int __init nft_quota_module_init(void)
|
|||
|
||||
return 0;
|
||||
err1:
|
||||
nft_unregister_obj(&nft_quota_obj);
|
||||
nft_unregister_obj(&nft_quota_obj_type);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit nft_quota_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_quota_type);
|
||||
nft_unregister_obj(&nft_quota_obj);
|
||||
nft_unregister_obj(&nft_quota_obj_type);
|
||||
}
|
||||
|
||||
module_init(nft_quota_module_init);
|
||||
|
|
Loading…
Reference in a new issue