netfilter: nf_tables: add select_ops for stateful objects
authorPablo M. Bermudo Garay <pablombg@gmail.com>
Wed, 23 Aug 2017 20:41:23 +0000 (22:41 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 4 Sep 2017 11:25:09 +0000 (13:25 +0200)
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>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_counter.c
net/netfilter/nft_ct.c
net/netfilter/nft_objref.c
net/netfilter/nft_quota.c

index f9795fe394f31333c0317aef01bc360763baa8a2..0f5b12a4ad09f0dd79ceb231e6de037ab830b039 100644 (file)
@@ -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);
index 149785ff1c7b695e95a30d5149f73edb96a7e796..b37c178897f38c952e965bf767ed10243c6ca046 100644 (file)
@@ -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 @@ err:
 
 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);
 }
index 67a710ebde09da21464da4bb22a78a36c791274d..eefe3b4099252f573ef3c7cbd9acafd273f9ea82 100644 (file)
@@ -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);
index 1678e9e75e8ee7d22301d6083ddeb04dd39ab385..bd0975d7dd6fe235418b904fe1b7cddd600b1663 100644 (file)
@@ -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 @@ err1:
 
 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);
 }
index 1dd428fbaaa3f836e7bcecb50355f60c14d8faad..7bcdc48f3d737a45758da58102638eab6f7cd7cf 100644 (file)
@@ -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,
index 25e33159be57882fcf9875725079188dfaa7d113..0ed124a93fcf3ee1149df52de147b19df712cfb9 100644 (file)
@@ -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);