Skip to content

Commit ef1f7df

Browse files
kaberummakynes
authored andcommitted
netfilter: nf_tables: expression ops overloading
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 <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 20a6934 commit ef1f7df

17 files changed

+267
-148
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -222,40 +222,56 @@ extern int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
222222
extern void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
223223
struct nft_set_binding *binding);
224224

225+
225226
/**
226-
* struct nft_expr_ops - nf_tables expression operations
227+
* struct nft_expr_type - nf_tables expression type
227228
*
228-
* @eval: Expression evaluation function
229-
* @init: initialization function
230-
* @destroy: destruction function
231-
* @dump: function to dump parameters
229+
* @select_ops: function to select nft_expr_ops
230+
* @ops: default ops, used when no select_ops functions is present
232231
* @list: used internally
233232
* @name: Identifier
234233
* @owner: module reference
235234
* @policy: netlink attribute policy
236235
* @maxattr: highest netlink attribute number
236+
*/
237+
struct nft_expr_type {
238+
const struct nft_expr_ops *(*select_ops)(const struct nlattr * const tb[]);
239+
const struct nft_expr_ops *ops;
240+
struct list_head list;
241+
const char *name;
242+
struct module *owner;
243+
const struct nla_policy *policy;
244+
unsigned int maxattr;
245+
};
246+
247+
/**
248+
* struct nft_expr_ops - nf_tables expression operations
249+
*
250+
* @eval: Expression evaluation function
237251
* @size: full expression size, including private data size
252+
* @init: initialization function
253+
* @destroy: destruction function
254+
* @dump: function to dump parameters
255+
* @type: expression type
238256
*/
239257
struct nft_expr;
240258
struct nft_expr_ops {
241259
void (*eval)(const struct nft_expr *expr,
242260
struct nft_data data[NFT_REG_MAX + 1],
243261
const struct nft_pktinfo *pkt);
262+
unsigned int size;
263+
244264
int (*init)(const struct nft_ctx *ctx,
245265
const struct nft_expr *expr,
246266
const struct nlattr * const tb[]);
247267
void (*destroy)(const struct nft_expr *expr);
248268
int (*dump)(struct sk_buff *skb,
249269
const struct nft_expr *expr);
250270
const struct nft_data * (*get_verdict)(const struct nft_expr *expr);
251-
struct list_head list;
252-
const char *name;
253-
struct module *owner;
254-
const struct nla_policy *policy;
255-
unsigned int maxattr;
256-
unsigned int size;
271+
const struct nft_expr_type *type;
257272
};
258273

274+
#define NFT_EXPR_MAXATTR 16
259275
#define NFT_EXPR_SIZE(size) (sizeof(struct nft_expr) + \
260276
ALIGN(size, __alignof__(struct nft_expr)))
261277

@@ -418,8 +434,8 @@ extern void nft_unregister_afinfo(struct nft_af_info *);
418434
extern int nft_register_table(struct nft_table *, int family);
419435
extern void nft_unregister_table(struct nft_table *, int family);
420436

421-
extern int nft_register_expr(struct nft_expr_ops *);
422-
extern void nft_unregister_expr(struct nft_expr_ops *);
437+
extern int nft_register_expr(struct nft_expr_type *);
438+
extern void nft_unregister_expr(struct nft_expr_type *);
423439

424440
#define MODULE_ALIAS_NFT_FAMILY(family) \
425441
MODULE_ALIAS("nft-afinfo-" __stringify(family))

net/ipv4/netfilter/nf_table_nat_ipv4.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008 Patrick McHardy <[email protected]>
2+
* Copyright (c) 2008-2009 Patrick McHardy <[email protected]>
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License version 2 as
@@ -149,15 +149,21 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
149149
return -1;
150150
}
151151

152-
static struct nft_expr_ops nft_nat_ops __read_mostly = {
153-
.name = "nat",
152+
static struct nft_expr_type nft_nat_type;
153+
static const struct nft_expr_ops nft_nat_ops = {
154+
.type = &nft_nat_type,
154155
.size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
155-
.owner = THIS_MODULE,
156156
.eval = nft_nat_eval,
157157
.init = nft_nat_init,
158158
.dump = nft_nat_dump,
159+
};
160+
161+
static struct nft_expr_type nft_nat_type __read_mostly = {
162+
.name = "nat",
163+
.ops = &nft_nat_ops,
159164
.policy = nft_nat_policy,
160165
.maxattr = NFTA_NAT_MAX,
166+
.owner = THIS_MODULE,
161167
};
162168

163169
/*
@@ -382,7 +388,7 @@ static int __init nf_table_nat_init(void)
382388
if (err < 0)
383389
goto err1;
384390

385-
err = nft_register_expr(&nft_nat_ops);
391+
err = nft_register_expr(&nft_nat_type);
386392
if (err < 0)
387393
goto err2;
388394

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

397403
static void __exit nf_table_nat_exit(void)
398404
{
399-
nft_unregister_expr(&nft_nat_ops);
405+
nft_unregister_expr(&nft_nat_type);
400406
nft_unregister_table(&nf_table_nat_ipv4, AF_INET);
401407
}
402408

net/ipv4/netfilter/nft_reject_ipv4.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008 Patrick McHardy <[email protected]>
2+
* Copyright (c) 2008-2009 Patrick McHardy <[email protected]>
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License version 2 as
@@ -88,25 +88,31 @@ static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
8888
return -1;
8989
}
9090

91-
static struct nft_expr_ops reject_ops __read_mostly = {
92-
.name = "reject",
91+
static struct nft_expr_type nft_reject_type;
92+
static const struct nft_expr_ops nft_reject_ops = {
93+
.type = &nft_reject_type,
9394
.size = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
94-
.owner = THIS_MODULE,
9595
.eval = nft_reject_eval,
9696
.init = nft_reject_init,
9797
.dump = nft_reject_dump,
98+
};
99+
100+
static struct nft_expr_type nft_reject_type __read_mostly = {
101+
.name = "reject",
102+
.ops = &nft_reject_ops,
98103
.policy = nft_reject_policy,
99104
.maxattr = NFTA_REJECT_MAX,
105+
.owner = THIS_MODULE,
100106
};
101107

102108
static int __init nft_reject_module_init(void)
103109
{
104-
return nft_register_expr(&reject_ops);
110+
return nft_register_expr(&nft_reject_type);
105111
}
106112

107113
static void __exit nft_reject_module_exit(void)
108114
{
109-
nft_unregister_expr(&reject_ops);
115+
nft_unregister_expr(&nft_reject_type);
110116
}
111117

112118
module_init(nft_reject_module_init);

net/netfilter/nf_tables_api.c

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -840,64 +840,64 @@ static void nft_ctx_init(struct nft_ctx *ctx,
840840
*/
841841

842842
/**
843-
* nft_register_expr - register nf_tables expr operations
844-
* @ops: expr operations
843+
* nft_register_expr - register nf_tables expr type
844+
* @ops: expr type
845845
*
846-
* Registers the expr operations for use with nf_tables. Returns zero on
846+
* Registers the expr type for use with nf_tables. Returns zero on
847847
* success or a negative errno code otherwise.
848848
*/
849-
int nft_register_expr(struct nft_expr_ops *ops)
849+
int nft_register_expr(struct nft_expr_type *type)
850850
{
851851
nfnl_lock(NFNL_SUBSYS_NFTABLES);
852-
list_add_tail(&ops->list, &nf_tables_expressions);
852+
list_add_tail(&type->list, &nf_tables_expressions);
853853
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
854854
return 0;
855855
}
856856
EXPORT_SYMBOL_GPL(nft_register_expr);
857857

858858
/**
859-
* nft_unregister_expr - unregister nf_tables expr operations
860-
* @ops: expr operations
859+
* nft_unregister_expr - unregister nf_tables expr type
860+
* @ops: expr type
861861
*
862-
* Unregisters the expr operations for use with nf_tables.
862+
* Unregisters the expr typefor use with nf_tables.
863863
*/
864-
void nft_unregister_expr(struct nft_expr_ops *ops)
864+
void nft_unregister_expr(struct nft_expr_type *type)
865865
{
866866
nfnl_lock(NFNL_SUBSYS_NFTABLES);
867-
list_del(&ops->list);
867+
list_del(&type->list);
868868
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
869869
}
870870
EXPORT_SYMBOL_GPL(nft_unregister_expr);
871871

872-
static const struct nft_expr_ops *__nft_expr_ops_get(struct nlattr *nla)
872+
static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
873873
{
874-
const struct nft_expr_ops *ops;
874+
const struct nft_expr_type *type;
875875

876-
list_for_each_entry(ops, &nf_tables_expressions, list) {
877-
if (!nla_strcmp(nla, ops->name))
878-
return ops;
876+
list_for_each_entry(type, &nf_tables_expressions, list) {
877+
if (!nla_strcmp(nla, type->name))
878+
return type;
879879
}
880880
return NULL;
881881
}
882882

883-
static const struct nft_expr_ops *nft_expr_ops_get(struct nlattr *nla)
883+
static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
884884
{
885-
const struct nft_expr_ops *ops;
885+
const struct nft_expr_type *type;
886886

887887
if (nla == NULL)
888888
return ERR_PTR(-EINVAL);
889889

890-
ops = __nft_expr_ops_get(nla);
891-
if (ops != NULL && try_module_get(ops->owner))
892-
return ops;
890+
type = __nft_expr_type_get(nla);
891+
if (type != NULL && try_module_get(type->owner))
892+
return type;
893893

894894
#ifdef CONFIG_MODULES
895-
if (ops == NULL) {
895+
if (type == NULL) {
896896
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
897897
request_module("nft-expr-%.*s",
898898
nla_len(nla), (char *)nla_data(nla));
899899
nfnl_lock(NFNL_SUBSYS_NFTABLES);
900-
if (__nft_expr_ops_get(nla))
900+
if (__nft_expr_type_get(nla))
901901
return ERR_PTR(-EAGAIN);
902902
}
903903
#endif
@@ -912,7 +912,7 @@ static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
912912
static int nf_tables_fill_expr_info(struct sk_buff *skb,
913913
const struct nft_expr *expr)
914914
{
915-
if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->name))
915+
if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
916916
goto nla_put_failure;
917917

918918
if (expr->ops->dump) {
@@ -932,52 +932,64 @@ static int nf_tables_fill_expr_info(struct sk_buff *skb,
932932

933933
struct nft_expr_info {
934934
const struct nft_expr_ops *ops;
935-
struct nlattr *tb[NFTA_EXPR_MAX + 1];
935+
struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
936936
};
937937

938938
static int nf_tables_expr_parse(const struct nlattr *nla,
939939
struct nft_expr_info *info)
940940
{
941+
const struct nft_expr_type *type;
941942
const struct nft_expr_ops *ops;
943+
struct nlattr *tb[NFTA_EXPR_MAX + 1];
942944
int err;
943945

944-
err = nla_parse_nested(info->tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
946+
err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
945947
if (err < 0)
946948
return err;
947949

948-
ops = nft_expr_ops_get(info->tb[NFTA_EXPR_NAME]);
949-
if (IS_ERR(ops))
950-
return PTR_ERR(ops);
950+
type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
951+
if (IS_ERR(type))
952+
return PTR_ERR(type);
953+
954+
if (tb[NFTA_EXPR_DATA]) {
955+
err = nla_parse_nested(info->tb, type->maxattr,
956+
tb[NFTA_EXPR_DATA], type->policy);
957+
if (err < 0)
958+
goto err1;
959+
} else
960+
memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
961+
962+
if (type->select_ops != NULL) {
963+
ops = type->select_ops((const struct nlattr * const *)info->tb);
964+
if (IS_ERR(ops)) {
965+
err = PTR_ERR(ops);
966+
goto err1;
967+
}
968+
} else
969+
ops = type->ops;
970+
951971
info->ops = ops;
952972
return 0;
973+
974+
err1:
975+
module_put(type->owner);
976+
return err;
953977
}
954978

955979
static int nf_tables_newexpr(const struct nft_ctx *ctx,
956-
struct nft_expr_info *info,
980+
const struct nft_expr_info *info,
957981
struct nft_expr *expr)
958982
{
959983
const struct nft_expr_ops *ops = info->ops;
960984
int err;
961985

962986
expr->ops = ops;
963987
if (ops->init) {
964-
struct nlattr *ma[ops->maxattr + 1];
965-
966-
if (info->tb[NFTA_EXPR_DATA]) {
967-
err = nla_parse_nested(ma, ops->maxattr,
968-
info->tb[NFTA_EXPR_DATA],
969-
ops->policy);
970-
if (err < 0)
971-
goto err1;
972-
} else
973-
memset(ma, 0, sizeof(ma[0]) * (ops->maxattr + 1));
974-
975-
err = ops->init(ctx, expr, (const struct nlattr **)ma);
988+
err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
976989
if (err < 0)
977990
goto err1;
978991
}
979992

980-
info->ops = NULL;
981993
return 0;
982994

983995
err1:
@@ -989,7 +1001,7 @@ static void nf_tables_expr_destroy(struct nft_expr *expr)
9891001
{
9901002
if (expr->ops->destroy)
9911003
expr->ops->destroy(expr);
992-
module_put(expr->ops->owner);
1004+
module_put(expr->ops->type->owner);
9931005
}
9941006

9951007
/*
@@ -1313,6 +1325,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
13131325
err = nf_tables_newexpr(&ctx, &info[i], expr);
13141326
if (err < 0)
13151327
goto err2;
1328+
info[i].ops = NULL;
13161329
expr = nft_expr_next(expr);
13171330
}
13181331

@@ -1341,7 +1354,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
13411354
err1:
13421355
for (i = 0; i < n; i++) {
13431356
if (info[i].ops != NULL)
1344-
module_put(info[i].ops->owner);
1357+
module_put(info[i].ops->type->owner);
13451358
}
13461359
return err;
13471360
}

0 commit comments

Comments
 (0)