extern void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
                                 struct nft_set_binding *binding);
 
+
 /**
- *     struct nft_expr_ops - nf_tables expression operations
+ *     struct nft_expr_type - nf_tables expression type
  *
- *     @eval: Expression evaluation function
- *     @init: initialization function
- *     @destroy: destruction function
- *     @dump: function to dump parameters
+ *     @select_ops: function to select nft_expr_ops
+ *     @ops: default ops, used when no select_ops functions is present
  *     @list: used internally
  *     @name: Identifier
  *     @owner: module reference
  *     @policy: netlink attribute policy
  *     @maxattr: highest netlink attribute number
+ */
+struct nft_expr_type {
+       const struct nft_expr_ops       *(*select_ops)(const struct nlattr * const tb[]);
+       const struct nft_expr_ops       *ops;
+       struct list_head                list;
+       const char                      *name;
+       struct module                   *owner;
+       const struct nla_policy         *policy;
+       unsigned int                    maxattr;
+};
+
+/**
+ *     struct nft_expr_ops - nf_tables expression operations
+ *
+ *     @eval: Expression evaluation function
  *     @size: full expression size, including private data size
+ *     @init: initialization function
+ *     @destroy: destruction function
+ *     @dump: function to dump parameters
+ *     @type: expression type
  */
 struct nft_expr;
 struct nft_expr_ops {
        void                            (*eval)(const struct nft_expr *expr,
                                                struct nft_data data[NFT_REG_MAX + 1],
                                                const struct nft_pktinfo *pkt);
+       unsigned int                    size;
+
        int                             (*init)(const struct nft_ctx *ctx,
                                                const struct nft_expr *expr,
                                                const struct nlattr * const tb[]);
        int                             (*dump)(struct sk_buff *skb,
                                                const struct nft_expr *expr);
        const struct nft_data *         (*get_verdict)(const struct nft_expr *expr);
-       struct list_head                list;
-       const char                      *name;
-       struct module                   *owner;
-       const struct nla_policy         *policy;
-       unsigned int                    maxattr;
-       unsigned int                    size;
+       const struct nft_expr_type      *type;
 };
 
+#define NFT_EXPR_MAXATTR               16
 #define NFT_EXPR_SIZE(size)            (sizeof(struct nft_expr) + \
                                         ALIGN(size, __alignof__(struct nft_expr)))
 
 extern int nft_register_table(struct nft_table *, int family);
 extern void nft_unregister_table(struct nft_table *, int family);
 
-extern int nft_register_expr(struct nft_expr_ops *);
-extern void nft_unregister_expr(struct nft_expr_ops *);
+extern int nft_register_expr(struct nft_expr_type *);
+extern void nft_unregister_expr(struct nft_expr_type *);
 
 #define MODULE_ALIAS_NFT_FAMILY(family)        \
        MODULE_ALIAS("nft-afinfo-" __stringify(family))
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_nat_ops __read_mostly = {
-       .name           = "nat",
+static struct nft_expr_type nft_nat_type;
+static const struct nft_expr_ops nft_nat_ops = {
+       .type           = &nft_nat_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
-       .owner          = THIS_MODULE,
        .eval           = nft_nat_eval,
        .init           = nft_nat_init,
        .dump           = nft_nat_dump,
+};
+
+static struct nft_expr_type nft_nat_type __read_mostly = {
+       .name           = "nat",
+       .ops            = &nft_nat_ops,
        .policy         = nft_nat_policy,
        .maxattr        = NFTA_NAT_MAX,
+       .owner          = THIS_MODULE,
 };
 
 /*
        if (err < 0)
                goto err1;
 
-       err = nft_register_expr(&nft_nat_ops);
+       err = nft_register_expr(&nft_nat_type);
        if (err < 0)
                goto err2;
 
 
 static void __exit nf_table_nat_exit(void)
 {
-       nft_unregister_expr(&nft_nat_ops);
+       nft_unregister_expr(&nft_nat_type);
        nft_unregister_table(&nf_table_nat_ipv4, AF_INET);
 }
 
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops reject_ops __read_mostly = {
-       .name           = "reject",
+static struct nft_expr_type nft_reject_type;
+static const struct nft_expr_ops nft_reject_ops = {
+       .type           = &nft_reject_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
-       .owner          = THIS_MODULE,
        .eval           = nft_reject_eval,
        .init           = nft_reject_init,
        .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_type __read_mostly = {
+       .name           = "reject",
+       .ops            = &nft_reject_ops,
        .policy         = nft_reject_policy,
        .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_reject_module_init(void)
 {
-       return nft_register_expr(&reject_ops);
+       return nft_register_expr(&nft_reject_type);
 }
 
 static void __exit nft_reject_module_exit(void)
 {
-       nft_unregister_expr(&reject_ops);
+       nft_unregister_expr(&nft_reject_type);
 }
 
 module_init(nft_reject_module_init);
 
  */
 
 /**
- *     nft_register_expr - register nf_tables expr operations
- *     @ops: expr operations
+ *     nft_register_expr - register nf_tables expr type
+ *     @ops: expr type
  *
- *     Registers the expr operations for use with nf_tables. Returns zero on
+ *     Registers the expr type for use with nf_tables. Returns zero on
  *     success or a negative errno code otherwise.
  */
-int nft_register_expr(struct nft_expr_ops *ops)
+int nft_register_expr(struct nft_expr_type *type)
 {
        nfnl_lock(NFNL_SUBSYS_NFTABLES);
-       list_add_tail(&ops->list, &nf_tables_expressions);
+       list_add_tail(&type->list, &nf_tables_expressions);
        nfnl_unlock(NFNL_SUBSYS_NFTABLES);
        return 0;
 }
 EXPORT_SYMBOL_GPL(nft_register_expr);
 
 /**
- *     nft_unregister_expr - unregister nf_tables expr operations
- *     @ops: expr operations
+ *     nft_unregister_expr - unregister nf_tables expr type
+ *     @ops: expr type
  *
- *     Unregisters the expr operations for use with nf_tables.
+ *     Unregisters the expr typefor use with nf_tables.
  */
-void nft_unregister_expr(struct nft_expr_ops *ops)
+void nft_unregister_expr(struct nft_expr_type *type)
 {
        nfnl_lock(NFNL_SUBSYS_NFTABLES);
-       list_del(&ops->list);
+       list_del(&type->list);
        nfnl_unlock(NFNL_SUBSYS_NFTABLES);
 }
 EXPORT_SYMBOL_GPL(nft_unregister_expr);
 
-static const struct nft_expr_ops *__nft_expr_ops_get(struct nlattr *nla)
+static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
 {
-       const struct nft_expr_ops *ops;
+       const struct nft_expr_type *type;
 
-       list_for_each_entry(ops, &nf_tables_expressions, list) {
-               if (!nla_strcmp(nla, ops->name))
-                       return ops;
+       list_for_each_entry(type, &nf_tables_expressions, list) {
+               if (!nla_strcmp(nla, type->name))
+                       return type;
        }
        return NULL;
 }
 
-static const struct nft_expr_ops *nft_expr_ops_get(struct nlattr *nla)
+static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
 {
-       const struct nft_expr_ops *ops;
+       const struct nft_expr_type *type;
 
        if (nla == NULL)
                return ERR_PTR(-EINVAL);
 
-       ops = __nft_expr_ops_get(nla);
-       if (ops != NULL && try_module_get(ops->owner))
-               return ops;
+       type = __nft_expr_type_get(nla);
+       if (type != NULL && try_module_get(type->owner))
+               return type;
 
 #ifdef CONFIG_MODULES
-       if (ops == NULL) {
+       if (type == NULL) {
                nfnl_unlock(NFNL_SUBSYS_NFTABLES);
                request_module("nft-expr-%.*s",
                               nla_len(nla), (char *)nla_data(nla));
                nfnl_lock(NFNL_SUBSYS_NFTABLES);
-               if (__nft_expr_ops_get(nla))
+               if (__nft_expr_type_get(nla))
                        return ERR_PTR(-EAGAIN);
        }
 #endif
 static int nf_tables_fill_expr_info(struct sk_buff *skb,
                                    const struct nft_expr *expr)
 {
-       if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->name))
+       if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
                goto nla_put_failure;
 
        if (expr->ops->dump) {
 
 struct nft_expr_info {
        const struct nft_expr_ops       *ops;
-       struct nlattr                   *tb[NFTA_EXPR_MAX + 1];
+       struct nlattr                   *tb[NFT_EXPR_MAXATTR + 1];
 };
 
 static int nf_tables_expr_parse(const struct nlattr *nla,
                                struct nft_expr_info *info)
 {
+       const struct nft_expr_type *type;
        const struct nft_expr_ops *ops;
+       struct nlattr *tb[NFTA_EXPR_MAX + 1];
        int err;
 
-       err = nla_parse_nested(info->tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
+       err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
        if (err < 0)
                return err;
 
-       ops = nft_expr_ops_get(info->tb[NFTA_EXPR_NAME]);
-       if (IS_ERR(ops))
-               return PTR_ERR(ops);
+       type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
+       if (IS_ERR(type))
+               return PTR_ERR(type);
+
+       if (tb[NFTA_EXPR_DATA]) {
+               err = nla_parse_nested(info->tb, type->maxattr,
+                                      tb[NFTA_EXPR_DATA], type->policy);
+               if (err < 0)
+                       goto err1;
+       } else
+               memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
+
+       if (type->select_ops != NULL) {
+               ops = type->select_ops((const struct nlattr * const *)info->tb);
+               if (IS_ERR(ops)) {
+                       err = PTR_ERR(ops);
+                       goto err1;
+               }
+       } else
+               ops = type->ops;
+
        info->ops = ops;
        return 0;
+
+err1:
+       module_put(type->owner);
+       return err;
 }
 
 static int nf_tables_newexpr(const struct nft_ctx *ctx,
-                            struct nft_expr_info *info,
+                            const struct nft_expr_info *info,
                             struct nft_expr *expr)
 {
        const struct nft_expr_ops *ops = info->ops;
 
        expr->ops = ops;
        if (ops->init) {
-               struct nlattr *ma[ops->maxattr + 1];
-
-               if (info->tb[NFTA_EXPR_DATA]) {
-                       err = nla_parse_nested(ma, ops->maxattr,
-                                              info->tb[NFTA_EXPR_DATA],
-                                              ops->policy);
-                       if (err < 0)
-                               goto err1;
-               } else
-                       memset(ma, 0, sizeof(ma[0]) * (ops->maxattr + 1));
-
-               err = ops->init(ctx, expr, (const struct nlattr **)ma);
+               err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
                if (err < 0)
                        goto err1;
        }
 
-       info->ops = NULL;
        return 0;
 
 err1:
 {
        if (expr->ops->destroy)
                expr->ops->destroy(expr);
-       module_put(expr->ops->owner);
+       module_put(expr->ops->type->owner);
 }
 
 /*
                err = nf_tables_newexpr(&ctx, &info[i], expr);
                if (err < 0)
                        goto err2;
+               info[i].ops = NULL;
                expr = nft_expr_next(expr);
        }
 
 err1:
        for (i = 0; i < n; i++) {
                if (info[i].ops != NULL)
-                       module_put(info[i].ops->owner);
+                       module_put(info[i].ops->type->owner);
        }
        return err;
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_bitwise_ops __read_mostly = {
-       .name           = "bitwise",
+static struct nft_expr_type nft_bitwise_type;
+static const struct nft_expr_ops nft_bitwise_ops = {
+       .type           = &nft_bitwise_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
-       .owner          = THIS_MODULE,
        .eval           = nft_bitwise_eval,
        .init           = nft_bitwise_init,
        .dump           = nft_bitwise_dump,
+};
+
+static struct nft_expr_type nft_bitwise_type __read_mostly = {
+       .name           = "bitwise",
+       .ops            = &nft_bitwise_ops,
        .policy         = nft_bitwise_policy,
        .maxattr        = NFTA_BITWISE_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_bitwise_module_init(void)
 {
-       return nft_register_expr(&nft_bitwise_ops);
+       return nft_register_expr(&nft_bitwise_type);
 }
 
 void nft_bitwise_module_exit(void)
 {
-       nft_unregister_expr(&nft_bitwise_ops);
+       nft_unregister_expr(&nft_bitwise_type);
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_byteorder_ops __read_mostly = {
-       .name           = "byteorder",
+static struct nft_expr_type nft_byteorder_type;
+static const struct nft_expr_ops nft_byteorder_ops = {
+       .type           = &nft_byteorder_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
-       .owner          = THIS_MODULE,
        .eval           = nft_byteorder_eval,
        .init           = nft_byteorder_init,
        .dump           = nft_byteorder_dump,
+};
+
+static struct nft_expr_type nft_byteorder_type __read_mostly = {
+       .name           = "byteorder",
+       .ops            = &nft_byteorder_ops,
        .policy         = nft_byteorder_policy,
        .maxattr        = NFTA_BYTEORDER_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_byteorder_module_init(void)
 {
-       return nft_register_expr(&nft_byteorder_ops);
+       return nft_register_expr(&nft_byteorder_type);
 }
 
 void nft_byteorder_module_exit(void)
 {
-       nft_unregister_expr(&nft_byteorder_ops);
+       nft_unregister_expr(&nft_byteorder_type);
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_cmp_ops __read_mostly = {
-       .name           = "cmp",
+static struct nft_expr_type nft_cmp_type;
+static const struct nft_expr_ops nft_cmp_ops = {
+       .type           = &nft_cmp_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_cmp_expr)),
-       .owner          = THIS_MODULE,
        .eval           = nft_cmp_eval,
        .init           = nft_cmp_init,
        .dump           = nft_cmp_dump,
+};
+
+static struct nft_expr_type nft_cmp_type __read_mostly = {
+       .name           = "cmp",
+       .ops            = &nft_cmp_ops,
        .policy         = nft_cmp_policy,
        .maxattr        = NFTA_CMP_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_cmp_module_init(void)
 {
-       return nft_register_expr(&nft_cmp_ops);
+       return nft_register_expr(&nft_cmp_type);
 }
 
 void nft_cmp_module_exit(void)
 {
-       nft_unregister_expr(&nft_cmp_ops);
+       nft_unregister_expr(&nft_cmp_type);
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return 0;
 }
 
-static struct nft_expr_ops nft_counter_ops __read_mostly = {
-       .name           = "counter",
+static struct nft_expr_type nft_counter_type;
+static const struct nft_expr_ops nft_counter_ops = {
+       .type           = &nft_counter_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_counter)),
-       .policy         = nft_counter_policy,
-       .maxattr        = NFTA_COUNTER_MAX,
-       .owner          = THIS_MODULE,
        .eval           = nft_counter_eval,
        .init           = nft_counter_init,
        .dump           = nft_counter_dump,
 };
 
+static struct nft_expr_type nft_counter_type __read_mostly = {
+       .name           = "counter",
+       .ops            = &nft_counter_ops,
+       .policy         = nft_counter_policy,
+       .maxattr        = NFTA_COUNTER_MAX,
+       .owner          = THIS_MODULE,
+};
+
 static int __init nft_counter_module_init(void)
 {
-       return nft_register_expr(&nft_counter_ops);
+       return nft_register_expr(&nft_counter_type);
 }
 
 static void __exit nft_counter_module_exit(void)
 {
-       nft_unregister_expr(&nft_counter_ops);
+       nft_unregister_expr(&nft_counter_type);
 }
 
 module_init(nft_counter_module_init);
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_ct_ops __read_mostly = {
-       .name           = "ct",
+static struct nft_expr_type nft_ct_type;
+static const struct nft_expr_ops nft_ct_ops = {
+       .type           = &nft_ct_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
-       .owner          = THIS_MODULE,
        .eval           = nft_ct_eval,
        .init           = nft_ct_init,
        .destroy        = nft_ct_destroy,
        .dump           = nft_ct_dump,
+};
+
+static struct nft_expr_type nft_ct_type __read_mostly = {
+       .name           = "ct",
+       .ops            = &nft_ct_ops,
        .policy         = nft_ct_policy,
        .maxattr        = NFTA_CT_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_ct_module_init(void)
 {
-       return nft_register_expr(&nft_ct_ops);
+       return nft_register_expr(&nft_ct_type);
 }
 
 static void __exit nft_ct_module_exit(void)
 {
-       nft_unregister_expr(&nft_ct_ops);
+       nft_unregister_expr(&nft_ct_type);
 }
 
 module_init(nft_ct_module_init);
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 
 static int nft_template_init(const struct nft_ctx *ctx,
                           const struct nft_expr *expr,
-                          const struct nlattr *tb[])
+                          const struct nlattr * const tb[])
 {
        struct nft_template *priv = nft_expr_priv(expr);
 
        return -1;
 }
 
-static struct nft_expr_ops template_ops __read_mostly = {
-       .name           = "template",
+static struct nft_expr_type nft_template_type;
+static const struct nft_expr_ops nft_template_ops = {
+       .type           = &nft_template_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_template)),
-       .owner          = THIS_MODULE,
        .eval           = nft_template_eval,
        .init           = nft_template_init,
        .destroy        = nft_template_destroy,
        .dump           = nft_template_dump,
+};
+
+static struct nft_expr_type nft_template_type __read_mostly = {
+       .name           = "template",
+       .ops            = &nft_template_ops,
        .policy         = nft_template_policy,
        .maxattr        = NFTA_TEMPLATE_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_template_module_init(void)
 {
-       return nft_register_expr(&template_ops);
+       return nft_register_expr(&nft_template_type);
 }
 
 static void __exit nft_template_module_exit(void)
 {
-       nft_unregister_expr(&template_ops);
+       nft_unregister_expr(&nft_template_type);
 }
 
 module_init(nft_template_module_init);
 
        return -1;
 }
 
-static struct nft_expr_ops exthdr_ops __read_mostly = {
-       .name           = "exthdr",
+static struct nft_expr_type nft_exthdr_type;
+static const struct nft_expr_ops nft_exthdr_ops = {
+       .type           = &nft_exthdr_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
-       .owner          = THIS_MODULE,
        .eval           = nft_exthdr_eval,
        .init           = nft_exthdr_init,
        .dump           = nft_exthdr_dump,
+};
+
+static struct nft_expr_type nft_exthdr_type __read_mostly = {
+       .name           = "exthdr",
+       .ops            = &nft_exthdr_ops,
        .policy         = nft_exthdr_policy,
        .maxattr        = NFTA_EXTHDR_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_exthdr_module_init(void)
 {
-       return nft_register_expr(&exthdr_ops);
+       return nft_register_expr(&nft_exthdr_type);
 }
 
 static void __exit nft_exthdr_module_exit(void)
 {
-       nft_unregister_expr(&exthdr_ops);
+       nft_unregister_expr(&nft_exthdr_type);
 }
 
 module_init(nft_exthdr_module_init);
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
                return NULL;
 }
 
-static struct nft_expr_ops nft_imm_ops __read_mostly = {
-       .name           = "immediate",
+static struct nft_expr_type nft_imm_type;
+static const struct nft_expr_ops nft_imm_ops = {
+       .type           = &nft_imm_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
-       .owner          = THIS_MODULE,
        .eval           = nft_immediate_eval,
        .init           = nft_immediate_init,
        .destroy        = nft_immediate_destroy,
        .dump           = nft_immediate_dump,
        .get_verdict    = nft_immediate_get_verdict,
+};
+
+static struct nft_expr_type nft_imm_type __read_mostly = {
+       .name           = "immediate",
+       .ops            = &nft_imm_ops,
        .policy         = nft_immediate_policy,
        .maxattr        = NFTA_IMMEDIATE_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_immediate_module_init(void)
 {
-       return nft_register_expr(&nft_imm_ops);
+       return nft_register_expr(&nft_imm_type);
 }
 
 void nft_immediate_module_exit(void)
 {
-       nft_unregister_expr(&nft_imm_ops);
+       nft_unregister_expr(&nft_imm_type);
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_limit_ops __read_mostly = {
-       .name           = "limit",
+static struct nft_expr_type nft_limit_type;
+static const struct nft_expr_ops nft_limit_ops = {
+       .type           = &nft_limit_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_limit)),
-       .owner          = THIS_MODULE,
        .eval           = nft_limit_eval,
        .init           = nft_limit_init,
        .dump           = nft_limit_dump,
+};
+
+static struct nft_expr_type nft_limit_type __read_mostly = {
+       .name           = "limit",
+       .ops            = &nft_limit_ops,
        .policy         = nft_limit_policy,
        .maxattr        = NFTA_LIMIT_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_limit_module_init(void)
 {
-       return nft_register_expr(&nft_limit_ops);
+       return nft_register_expr(&nft_limit_type);
 }
 
 static void __exit nft_limit_module_exit(void)
 {
-       nft_unregister_expr(&nft_limit_ops);
+       nft_unregister_expr(&nft_limit_type);
 }
 
 module_init(nft_limit_module_init);
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_log_ops __read_mostly = {
-       .name           = "log",
+static struct nft_expr_type nft_log_type;
+static const struct nft_expr_ops nft_log_ops = {
+       .type           = &nft_log_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_log)),
-       .owner          = THIS_MODULE,
        .eval           = nft_log_eval,
        .init           = nft_log_init,
        .destroy        = nft_log_destroy,
        .dump           = nft_log_dump,
+};
+
+static struct nft_expr_type nft_log_type __read_mostly = {
+       .name           = "log",
+       .ops            = &nft_log_ops,
        .policy         = nft_log_policy,
        .maxattr        = NFTA_LOG_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_log_module_init(void)
 {
-       return nft_register_expr(&nft_log_ops);
+       return nft_register_expr(&nft_log_type);
 }
 
 static void __exit nft_log_module_exit(void)
 {
-       nft_unregister_expr(&nft_log_ops);
+       nft_unregister_expr(&nft_log_type);
 }
 
 module_init(nft_log_module_init);
 
        return -1;
 }
 
-static struct nft_expr_ops nft_lookup_ops __read_mostly = {
-       .name           = "lookup",
+static struct nft_expr_type nft_lookup_type;
+static const struct nft_expr_ops nft_lookup_ops = {
+       .type           = &nft_lookup_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
-       .owner          = THIS_MODULE,
        .eval           = nft_lookup_eval,
        .init           = nft_lookup_init,
        .destroy        = nft_lookup_destroy,
        .dump           = nft_lookup_dump,
+};
+
+static struct nft_expr_type nft_lookup_type __read_mostly = {
+       .name           = "lookup",
+       .ops            = &nft_lookup_ops,
        .policy         = nft_lookup_policy,
        .maxattr        = NFTA_LOOKUP_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_lookup_module_init(void)
 {
-       return nft_register_expr(&nft_lookup_ops);
+       return nft_register_expr(&nft_lookup_type);
 }
 
 void nft_lookup_module_exit(void)
 {
-       nft_unregister_expr(&nft_lookup_ops);
+       nft_unregister_expr(&nft_lookup_type);
 }
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_meta_ops __read_mostly = {
-       .name           = "meta",
+static struct nft_expr_type nft_meta_type;
+static const struct nft_expr_ops nft_meta_ops = {
+       .type           = &nft_meta_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
-       .owner          = THIS_MODULE,
        .eval           = nft_meta_eval,
        .init           = nft_meta_init,
        .dump           = nft_meta_dump,
+};
+
+static struct nft_expr_type nft_meta_type __read_mostly = {
+       .name           = "meta",
+       .ops            = &nft_meta_ops,
        .policy         = nft_meta_policy,
        .maxattr        = NFTA_META_MAX,
+       .owner          = THIS_MODULE,
 };
 
 static int __init nft_meta_module_init(void)
 {
-       return nft_register_expr(&nft_meta_ops);
+       return nft_register_expr(&nft_meta_type);
 }
 
 static void __exit nft_meta_module_exit(void)
 {
-       nft_unregister_expr(&nft_meta_ops);
+       nft_unregister_expr(&nft_meta_type);
 }
 
 module_init(nft_meta_module_init);
 
 /*
- * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return -1;
 }
 
-static struct nft_expr_ops nft_payload_ops __read_mostly = {
-       .name           = "payload",
+static struct nft_expr_type nft_payload_type;
+static const struct nft_expr_ops nft_payload_ops = {
+       .type           = &nft_payload_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
-       .owner          = THIS_MODULE,
        .eval           = nft_payload_eval,
        .init           = nft_payload_init,
        .dump           = nft_payload_dump,
+};
+
+static struct nft_expr_type nft_payload_type __read_mostly = {
+       .name           = "payload",
+       .ops            = &nft_payload_ops,
        .policy         = nft_payload_policy,
        .maxattr        = NFTA_PAYLOAD_MAX,
+       .owner          = THIS_MODULE,
 };
 
 int __init nft_payload_module_init(void)
 {
-       return nft_register_expr(&nft_payload_ops);
+       return nft_register_expr(&nft_payload_type);
 }
 
 void nft_payload_module_exit(void)
 {
-       nft_unregister_expr(&nft_payload_ops);
+       nft_unregister_expr(&nft_payload_type);
 }