Skip to content

Commit

Permalink
netfilter: nf_tables: expression ops overloading
Browse files Browse the repository at this point in the history
Split the expression ops into two parts and support overloading of
the runtime expression ops based on the requested function through
a ->select_ops() callback.

This can be used to provide optimized implementations, for instance
for loading small aligned amounts of data from the packet or inlining
frequently used operations into the main evaluation loop.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Patrick McHardy authored and Pablo Neira Ayuso committed Oct 14, 2013
1 parent 20a6934 commit ef1f7df
Show file tree
Hide file tree
Showing 17 changed files with 267 additions and 148 deletions.
42 changes: 29 additions & 13 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,40 +222,56 @@ extern int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
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[]);
void (*destroy)(const struct nft_expr *expr);
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)))

Expand Down Expand Up @@ -418,8 +434,8 @@ extern void nft_unregister_afinfo(struct nft_af_info *);
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))
Expand Down
18 changes: 12 additions & 6 deletions net/ipv4/netfilter/nf_table_nat_ipv4.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* 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
Expand Down Expand Up @@ -149,15 +149,21 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
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,
};

/*
Expand Down Expand Up @@ -382,7 +388,7 @@ static int __init nf_table_nat_init(void)
if (err < 0)
goto err1;

err = nft_register_expr(&nft_nat_ops);
err = nft_register_expr(&nft_nat_type);
if (err < 0)
goto err2;

Expand All @@ -396,7 +402,7 @@ static int __init nf_table_nat_init(void)

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);
}

Expand Down
18 changes: 12 additions & 6 deletions net/ipv4/netfilter/nft_reject_ipv4.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* 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
Expand Down Expand Up @@ -88,25 +88,31 @@ static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
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);
Expand Down
101 changes: 57 additions & 44 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -840,64 +840,64 @@ static void nft_ctx_init(struct nft_ctx *ctx,
*/

/**
* 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
Expand All @@ -912,7 +912,7 @@ static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
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) {
Expand All @@ -932,52 +932,64 @@ static int nf_tables_fill_expr_info(struct sk_buff *skb,

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;
int err;

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:
Expand All @@ -989,7 +1001,7 @@ static void nf_tables_expr_destroy(struct nft_expr *expr)
{
if (expr->ops->destroy)
expr->ops->destroy(expr);
module_put(expr->ops->owner);
module_put(expr->ops->type->owner);
}

/*
Expand Down Expand Up @@ -1313,6 +1325,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
err = nf_tables_newexpr(&ctx, &info[i], expr);
if (err < 0)
goto err2;
info[i].ops = NULL;
expr = nft_expr_next(expr);
}

Expand Down Expand Up @@ -1341,7 +1354,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
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;
}
Expand Down
Loading

0 comments on commit ef1f7df

Please sign in to comment.