aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2018-01-06 19:04:07 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2018-01-08 12:11:06 -0500
commit3b49e2e94e6ebb8b23d0955d9e898254455734f8 (patch)
tree4813ba6f535ed50d5e4472fcc15d09c755726ac2
parent90964016e5d34758033e75884e41d68ccb93212e (diff)
netfilter: nf_tables: add flow table netlink frontend
This patch introduces a netlink control plane to create, delete and dump flow tables. Flow tables are identified by name, this name is used from rules to refer to an specific flow table. Flow tables use the rhashtable class and a generic garbage collector to remove expired entries. This also adds the infrastructure to add different flow table types, so we can add one for each layer 3 protocol family. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/net/netfilter/nf_flow_table.h23
-rw-r--r--include/net/netfilter/nf_tables.h48
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h53
-rw-r--r--net/netfilter/nf_tables_api.c747
4 files changed, 870 insertions, 1 deletions
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
new file mode 100644
index 000000000000..3a0779589281
--- /dev/null
+++ b/include/net/netfilter/nf_flow_table.h
@@ -0,0 +1,23 @@
1#ifndef _NF_FLOW_TABLE_H
2#define _NF_FLOW_TABLE_H
3
4#include <linux/rhashtable.h>
5
6struct nf_flowtable;
7
8struct nf_flowtable_type {
9 struct list_head list;
10 int family;
11 void (*gc)(struct work_struct *work);
12 const struct rhashtable_params *params;
13 nf_hookfn *hook;
14 struct module *owner;
15};
16
17struct nf_flowtable {
18 struct rhashtable rhashtable;
19 const struct nf_flowtable_type *type;
20 struct delayed_work gc_work;
21};
22
23#endif /* _FLOW_OFFLOAD_H */
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index e3ec02fd0f67..dd238950df81 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -9,6 +9,7 @@
9#include <linux/netfilter/x_tables.h> 9#include <linux/netfilter/x_tables.h>
10#include <linux/netfilter/nf_tables.h> 10#include <linux/netfilter/nf_tables.h>
11#include <linux/u64_stats_sync.h> 11#include <linux/u64_stats_sync.h>
12#include <net/netfilter/nf_flow_table.h>
12#include <net/netlink.h> 13#include <net/netlink.h>
13 14
14#define NFT_JUMP_STACK_SIZE 16 15#define NFT_JUMP_STACK_SIZE 16
@@ -943,6 +944,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
943 * @chains: chains in the table 944 * @chains: chains in the table
944 * @sets: sets in the table 945 * @sets: sets in the table
945 * @objects: stateful objects in the table 946 * @objects: stateful objects in the table
947 * @flowtables: flow tables in the table
946 * @hgenerator: handle generator state 948 * @hgenerator: handle generator state
947 * @use: number of chain references to this table 949 * @use: number of chain references to this table
948 * @flags: table flag (see enum nft_table_flags) 950 * @flags: table flag (see enum nft_table_flags)
@@ -954,6 +956,7 @@ struct nft_table {
954 struct list_head chains; 956 struct list_head chains;
955 struct list_head sets; 957 struct list_head sets;
956 struct list_head objects; 958 struct list_head objects;
959 struct list_head flowtables;
957 u64 hgenerator; 960 u64 hgenerator;
958 u32 use; 961 u32 use;
959 u16 flags:14, 962 u16 flags:14,
@@ -1085,6 +1088,44 @@ int nft_register_obj(struct nft_object_type *obj_type);
1085void nft_unregister_obj(struct nft_object_type *obj_type); 1088void nft_unregister_obj(struct nft_object_type *obj_type);
1086 1089
1087/** 1090/**
1091 * struct nft_flowtable - nf_tables flow table
1092 *
1093 * @list: flow table list node in table list
1094 * @table: the table the flow table is contained in
1095 * @name: name of this flow table
1096 * @hooknum: hook number
1097 * @priority: hook priority
1098 * @ops_len: number of hooks in array
1099 * @genmask: generation mask
1100 * @use: number of references to this flow table
1101 * @data: rhashtable and garbage collector
1102 * @ops: array of hooks
1103 */
1104struct nft_flowtable {
1105 struct list_head list;
1106 struct nft_table *table;
1107 char *name;
1108 int hooknum;
1109 int priority;
1110 int ops_len;
1111 u32 genmask:2,
1112 use:30;
1113 /* runtime data below here */
1114 struct nf_hook_ops *ops ____cacheline_aligned;
1115 struct nf_flowtable data;
1116};
1117
1118struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
1119 const struct nlattr *nla,
1120 u8 genmask);
1121void nft_flow_table_iterate(struct net *net,
1122 void (*iter)(struct nf_flowtable *flowtable, void *data),
1123 void *data);
1124
1125void nft_register_flowtable_type(struct nf_flowtable_type *type);
1126void nft_unregister_flowtable_type(struct nf_flowtable_type *type);
1127
1128/**
1088 * struct nft_traceinfo - nft tracing information and state 1129 * struct nft_traceinfo - nft tracing information and state
1089 * 1130 *
1090 * @pkt: pktinfo currently processed 1131 * @pkt: pktinfo currently processed
@@ -1317,4 +1358,11 @@ struct nft_trans_obj {
1317#define nft_trans_obj(trans) \ 1358#define nft_trans_obj(trans) \
1318 (((struct nft_trans_obj *)trans->data)->obj) 1359 (((struct nft_trans_obj *)trans->data)->obj)
1319 1360
1361struct nft_trans_flowtable {
1362 struct nft_flowtable *flowtable;
1363};
1364
1365#define nft_trans_flowtable(trans) \
1366 (((struct nft_trans_flowtable *)trans->data)->flowtable)
1367
1320#endif /* _NET_NF_TABLES_H */ 1368#endif /* _NET_NF_TABLES_H */
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 2efbf9744c2a..591b53bce070 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -92,6 +92,9 @@ enum nft_verdicts {
92 * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes) 92 * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
93 * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes) 93 * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
94 * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes) 94 * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
95 * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
96 * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
97 * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
95 */ 98 */
96enum nf_tables_msg_types { 99enum nf_tables_msg_types {
97 NFT_MSG_NEWTABLE, 100 NFT_MSG_NEWTABLE,
@@ -116,6 +119,9 @@ enum nf_tables_msg_types {
116 NFT_MSG_GETOBJ, 119 NFT_MSG_GETOBJ,
117 NFT_MSG_DELOBJ, 120 NFT_MSG_DELOBJ,
118 NFT_MSG_GETOBJ_RESET, 121 NFT_MSG_GETOBJ_RESET,
122 NFT_MSG_NEWFLOWTABLE,
123 NFT_MSG_GETFLOWTABLE,
124 NFT_MSG_DELFLOWTABLE,
119 NFT_MSG_MAX, 125 NFT_MSG_MAX,
120}; 126};
121 127
@@ -1310,6 +1316,53 @@ enum nft_object_attributes {
1310#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) 1316#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
1311 1317
1312/** 1318/**
1319 * enum nft_flowtable_attributes - nf_tables flow table netlink attributes
1320 *
1321 * @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
1322 * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
1323 * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
1324 * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
1325 */
1326enum nft_flowtable_attributes {
1327 NFTA_FLOWTABLE_UNSPEC,
1328 NFTA_FLOWTABLE_TABLE,
1329 NFTA_FLOWTABLE_NAME,
1330 NFTA_FLOWTABLE_HOOK,
1331 NFTA_FLOWTABLE_USE,
1332 __NFTA_FLOWTABLE_MAX
1333};
1334#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
1335
1336/**
1337 * enum nft_flowtable_hook_attributes - nf_tables flow table hook netlink attributes
1338 *
1339 * @NFTA_FLOWTABLE_HOOK_NUM: netfilter hook number (NLA_U32)
1340 * @NFTA_FLOWTABLE_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
1341 * @NFTA_FLOWTABLE_HOOK_DEVS: input devices this flow table is bound to (NLA_NESTED)
1342 */
1343enum nft_flowtable_hook_attributes {
1344 NFTA_FLOWTABLE_HOOK_UNSPEC,
1345 NFTA_FLOWTABLE_HOOK_NUM,
1346 NFTA_FLOWTABLE_HOOK_PRIORITY,
1347 NFTA_FLOWTABLE_HOOK_DEVS,
1348 __NFTA_FLOWTABLE_HOOK_MAX
1349};
1350#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
1351
1352/**
1353 * enum nft_device_attributes - nf_tables device netlink attributes
1354 *
1355 * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
1356 */
1357enum nft_devices_attributes {
1358 NFTA_DEVICE_UNSPEC,
1359 NFTA_DEVICE_NAME,
1360 __NFTA_DEVICE_MAX
1361};
1362#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
1363
1364
1365/**
1313 * enum nft_trace_attributes - nf_tables trace netlink attributes 1366 * enum nft_trace_attributes - nf_tables trace netlink attributes
1314 * 1367 *
1315 * @NFTA_TRACE_TABLE: name of the table (NLA_STRING) 1368 * @NFTA_TRACE_TABLE: name of the table (NLA_STRING)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index fa564dac66a2..db0933256ec9 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -17,6 +17,7 @@
17#include <linux/netfilter.h> 17#include <linux/netfilter.h>
18#include <linux/netfilter/nfnetlink.h> 18#include <linux/netfilter/nfnetlink.h>
19#include <linux/netfilter/nf_tables.h> 19#include <linux/netfilter/nf_tables.h>
20#include <net/netfilter/nf_flow_table.h>
20#include <net/netfilter/nf_tables_core.h> 21#include <net/netfilter/nf_tables_core.h>
21#include <net/netfilter/nf_tables.h> 22#include <net/netfilter/nf_tables.h>
22#include <net/net_namespace.h> 23#include <net/net_namespace.h>
@@ -24,6 +25,7 @@
24 25
25static LIST_HEAD(nf_tables_expressions); 26static LIST_HEAD(nf_tables_expressions);
26static LIST_HEAD(nf_tables_objects); 27static LIST_HEAD(nf_tables_objects);
28static LIST_HEAD(nf_tables_flowtables);
27 29
28/** 30/**
29 * nft_register_afinfo - register nf_tables address family info 31 * nft_register_afinfo - register nf_tables address family info
@@ -345,6 +347,40 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
345 return err; 347 return err;
346} 348}
347 349
350static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
351 struct nft_flowtable *flowtable)
352{
353 struct nft_trans *trans;
354
355 trans = nft_trans_alloc(ctx, msg_type,
356 sizeof(struct nft_trans_flowtable));
357 if (trans == NULL)
358 return -ENOMEM;
359
360 if (msg_type == NFT_MSG_NEWFLOWTABLE)
361 nft_activate_next(ctx->net, flowtable);
362
363 nft_trans_flowtable(trans) = flowtable;
364 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
365
366 return 0;
367}
368
369static int nft_delflowtable(struct nft_ctx *ctx,
370 struct nft_flowtable *flowtable)
371{
372 int err;
373
374 err = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
375 if (err < 0)
376 return err;
377
378 nft_deactivate_next(ctx->net, flowtable);
379 ctx->table->use--;
380
381 return err;
382}
383
348/* 384/*
349 * Tables 385 * Tables
350 */ 386 */
@@ -728,6 +764,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
728 INIT_LIST_HEAD(&table->chains); 764 INIT_LIST_HEAD(&table->chains);
729 INIT_LIST_HEAD(&table->sets); 765 INIT_LIST_HEAD(&table->sets);
730 INIT_LIST_HEAD(&table->objects); 766 INIT_LIST_HEAD(&table->objects);
767 INIT_LIST_HEAD(&table->flowtables);
731 table->flags = flags; 768 table->flags = flags;
732 769
733 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla); 770 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
@@ -749,10 +786,11 @@ err1:
749 786
750static int nft_flush_table(struct nft_ctx *ctx) 787static int nft_flush_table(struct nft_ctx *ctx)
751{ 788{
752 int err; 789 struct nft_flowtable *flowtable, *nft;
753 struct nft_chain *chain, *nc; 790 struct nft_chain *chain, *nc;
754 struct nft_object *obj, *ne; 791 struct nft_object *obj, *ne;
755 struct nft_set *set, *ns; 792 struct nft_set *set, *ns;
793 int err;
756 794
757 list_for_each_entry(chain, &ctx->table->chains, list) { 795 list_for_each_entry(chain, &ctx->table->chains, list) {
758 if (!nft_is_active_next(ctx->net, chain)) 796 if (!nft_is_active_next(ctx->net, chain))
@@ -778,6 +816,12 @@ static int nft_flush_table(struct nft_ctx *ctx)
778 goto out; 816 goto out;
779 } 817 }
780 818
819 list_for_each_entry_safe(flowtable, nft, &ctx->table->flowtables, list) {
820 err = nft_delflowtable(ctx, flowtable);
821 if (err < 0)
822 goto out;
823 }
824
781 list_for_each_entry_safe(obj, ne, &ctx->table->objects, list) { 825 list_for_each_entry_safe(obj, ne, &ctx->table->objects, list) {
782 err = nft_delobj(ctx, obj); 826 err = nft_delobj(ctx, obj);
783 if (err < 0) 827 if (err < 0)
@@ -4839,6 +4883,605 @@ static void nf_tables_obj_notify(const struct nft_ctx *ctx,
4839 ctx->afi->family, ctx->report, GFP_KERNEL); 4883 ctx->afi->family, ctx->report, GFP_KERNEL);
4840} 4884}
4841 4885
4886/*
4887 * Flow tables
4888 */
4889void nft_register_flowtable_type(struct nf_flowtable_type *type)
4890{
4891 nfnl_lock(NFNL_SUBSYS_NFTABLES);
4892 list_add_tail_rcu(&type->list, &nf_tables_flowtables);
4893 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
4894}
4895EXPORT_SYMBOL_GPL(nft_register_flowtable_type);
4896
4897void nft_unregister_flowtable_type(struct nf_flowtable_type *type)
4898{
4899 nfnl_lock(NFNL_SUBSYS_NFTABLES);
4900 list_del_rcu(&type->list);
4901 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
4902}
4903EXPORT_SYMBOL_GPL(nft_unregister_flowtable_type);
4904
4905static const struct nla_policy nft_flowtable_policy[NFTA_FLOWTABLE_MAX + 1] = {
4906 [NFTA_FLOWTABLE_TABLE] = { .type = NLA_STRING,
4907 .len = NFT_NAME_MAXLEN - 1 },
4908 [NFTA_FLOWTABLE_NAME] = { .type = NLA_STRING,
4909 .len = NFT_NAME_MAXLEN - 1 },
4910 [NFTA_FLOWTABLE_HOOK] = { .type = NLA_NESTED },
4911};
4912
4913struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
4914 const struct nlattr *nla,
4915 u8 genmask)
4916{
4917 struct nft_flowtable *flowtable;
4918
4919 list_for_each_entry(flowtable, &table->flowtables, list) {
4920 if (!nla_strcmp(nla, flowtable->name) &&
4921 nft_active_genmask(flowtable, genmask))
4922 return flowtable;
4923 }
4924 return ERR_PTR(-ENOENT);
4925}
4926EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
4927
4928#define NFT_FLOWTABLE_DEVICE_MAX 8
4929
4930static int nf_tables_parse_devices(const struct nft_ctx *ctx,
4931 const struct nlattr *attr,
4932 struct net_device *dev_array[], int *len)
4933{
4934 const struct nlattr *tmp;
4935 struct net_device *dev;
4936 char ifname[IFNAMSIZ];
4937 int rem, n = 0, err;
4938
4939 nla_for_each_nested(tmp, attr, rem) {
4940 if (nla_type(tmp) != NFTA_DEVICE_NAME) {
4941 err = -EINVAL;
4942 goto err1;
4943 }
4944
4945 nla_strlcpy(ifname, tmp, IFNAMSIZ);
4946 dev = dev_get_by_name(ctx->net, ifname);
4947 if (!dev) {
4948 err = -ENOENT;
4949 goto err1;
4950 }
4951
4952 dev_array[n++] = dev;
4953 if (n == NFT_FLOWTABLE_DEVICE_MAX) {
4954 err = -EFBIG;
4955 goto err1;
4956 }
4957 }
4958 if (!len)
4959 return -EINVAL;
4960
4961 err = 0;
4962err1:
4963 *len = n;
4964 return err;
4965}
4966
4967static const struct nla_policy nft_flowtable_hook_policy[NFTA_FLOWTABLE_HOOK_MAX + 1] = {
4968 [NFTA_FLOWTABLE_HOOK_NUM] = { .type = NLA_U32 },
4969 [NFTA_FLOWTABLE_HOOK_PRIORITY] = { .type = NLA_U32 },
4970 [NFTA_FLOWTABLE_HOOK_DEVS] = { .type = NLA_NESTED },
4971};
4972
4973static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
4974 const struct nlattr *attr,
4975 struct nft_flowtable *flowtable)
4976{
4977 struct net_device *dev_array[NFT_FLOWTABLE_DEVICE_MAX];
4978 struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1];
4979 struct nf_hook_ops *ops;
4980 int hooknum, priority;
4981 int err, n = 0, i;
4982
4983 err = nla_parse_nested(tb, NFTA_FLOWTABLE_HOOK_MAX, attr,
4984 nft_flowtable_hook_policy, NULL);
4985 if (err < 0)
4986 return err;
4987
4988 if (!tb[NFTA_FLOWTABLE_HOOK_NUM] ||
4989 !tb[NFTA_FLOWTABLE_HOOK_PRIORITY] ||
4990 !tb[NFTA_FLOWTABLE_HOOK_DEVS])
4991 return -EINVAL;
4992
4993 hooknum = ntohl(nla_get_be32(tb[NFTA_FLOWTABLE_HOOK_NUM]));
4994 if (hooknum >= ctx->afi->nhooks)
4995 return -EINVAL;
4996
4997 priority = ntohl(nla_get_be32(tb[NFTA_FLOWTABLE_HOOK_PRIORITY]));
4998
4999 err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS],
5000 dev_array, &n);
5001 if (err < 0)
5002 goto err1;
5003
5004 ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
5005 if (!ops) {
5006 err = -ENOMEM;
5007 goto err1;
5008 }
5009
5010 flowtable->ops = ops;
5011 flowtable->ops_len = n;
5012
5013 for (i = 0; i < n; i++) {
5014 flowtable->ops[i].pf = NFPROTO_NETDEV;
5015 flowtable->ops[i].hooknum = hooknum;
5016 flowtable->ops[i].priority = priority;
5017 flowtable->ops[i].priv = &flowtable->data.rhashtable;
5018 flowtable->ops[i].hook = flowtable->data.type->hook;
5019 flowtable->ops[i].dev = dev_array[i];
5020 }
5021
5022 err = 0;
5023err1:
5024 for (i = 0; i < n; i++)
5025 dev_put(dev_array[i]);
5026
5027 return err;
5028}
5029
5030static const struct nf_flowtable_type *
5031__nft_flowtable_type_get(const struct nft_af_info *afi)
5032{
5033 const struct nf_flowtable_type *type;
5034
5035 list_for_each_entry(type, &nf_tables_flowtables, list) {
5036 if (afi->family == type->family)
5037 return type;
5038 }
5039 return NULL;
5040}
5041
5042static const struct nf_flowtable_type *
5043nft_flowtable_type_get(const struct nft_af_info *afi)
5044{
5045 const struct nf_flowtable_type *type;
5046
5047 type = __nft_flowtable_type_get(afi);
5048 if (type != NULL && try_module_get(type->owner))
5049 return type;
5050
5051#ifdef CONFIG_MODULES
5052 if (type == NULL) {
5053 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
5054 request_module("nf-flowtable-%u", afi->family);
5055 nfnl_lock(NFNL_SUBSYS_NFTABLES);
5056 if (__nft_flowtable_type_get(afi))
5057 return ERR_PTR(-EAGAIN);
5058 }
5059#endif
5060 return ERR_PTR(-ENOENT);
5061}
5062
5063void nft_flow_table_iterate(struct net *net,
5064 void (*iter)(struct nf_flowtable *flowtable, void *data),
5065 void *data)
5066{
5067 struct nft_flowtable *flowtable;
5068 const struct nft_af_info *afi;
5069 const struct nft_table *table;
5070
5071 rcu_read_lock();
5072 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
5073 list_for_each_entry_rcu(table, &afi->tables, list) {
5074 list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
5075 iter(&flowtable->data, data);
5076 }
5077 }
5078 }
5079 rcu_read_unlock();
5080}
5081EXPORT_SYMBOL_GPL(nft_flow_table_iterate);
5082
5083static void nft_unregister_flowtable_net_hooks(struct net *net,
5084 struct nft_flowtable *flowtable)
5085{
5086 int i;
5087
5088 for (i = 0; i < flowtable->ops_len; i++) {
5089 if (!flowtable->ops[i].dev)
5090 continue;
5091
5092 nf_unregister_net_hook(net, &flowtable->ops[i]);
5093 }
5094}
5095
5096static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
5097 struct sk_buff *skb,
5098 const struct nlmsghdr *nlh,
5099 const struct nlattr * const nla[],
5100 struct netlink_ext_ack *extack)
5101{
5102 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
5103 const struct nf_flowtable_type *type;
5104 u8 genmask = nft_genmask_next(net);
5105 int family = nfmsg->nfgen_family;
5106 struct nft_flowtable *flowtable;
5107 struct nft_af_info *afi;
5108 struct nft_table *table;
5109 struct nft_ctx ctx;
5110 int err, i, k;
5111
5112 if (!nla[NFTA_FLOWTABLE_TABLE] ||
5113 !nla[NFTA_FLOWTABLE_NAME] ||
5114 !nla[NFTA_FLOWTABLE_HOOK])
5115 return -EINVAL;
5116
5117 afi = nf_tables_afinfo_lookup(net, family, true);
5118 if (IS_ERR(afi))
5119 return PTR_ERR(afi);
5120
5121 table = nf_tables_table_lookup(afi, nla[NFTA_FLOWTABLE_TABLE], genmask);
5122 if (IS_ERR(table))
5123 return PTR_ERR(table);
5124
5125 flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
5126 genmask);
5127 if (IS_ERR(flowtable)) {
5128 err = PTR_ERR(flowtable);
5129 if (err != -ENOENT)
5130 return err;
5131 } else {
5132 if (nlh->nlmsg_flags & NLM_F_EXCL)
5133 return -EEXIST;
5134
5135 return 0;
5136 }
5137
5138 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
5139
5140 flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL);
5141 if (!flowtable)
5142 return -ENOMEM;
5143
5144 flowtable->table = table;
5145 flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
5146 if (!flowtable->name) {
5147 err = -ENOMEM;
5148 goto err1;
5149 }
5150
5151 type = nft_flowtable_type_get(afi);
5152 if (IS_ERR(type)) {
5153 err = PTR_ERR(type);
5154 goto err2;
5155 }
5156
5157 flowtable->data.type = type;
5158 err = rhashtable_init(&flowtable->data.rhashtable, type->params);
5159 if (err < 0)
5160 goto err3;
5161
5162 err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK],
5163 flowtable);
5164 if (err < 0)
5165 goto err3;
5166
5167 for (i = 0; i < flowtable->ops_len; i++) {
5168 err = nf_register_net_hook(net, &flowtable->ops[i]);
5169 if (err < 0)
5170 goto err4;
5171 }
5172
5173 err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
5174 if (err < 0)
5175 goto err5;
5176
5177 INIT_DEFERRABLE_WORK(&flowtable->data.gc_work, type->gc);
5178 queue_delayed_work(system_power_efficient_wq,
5179 &flowtable->data.gc_work, HZ);
5180
5181 list_add_tail_rcu(&flowtable->list, &table->flowtables);
5182 table->use++;
5183
5184 return 0;
5185err5:
5186 i = flowtable->ops_len;
5187err4:
5188 for (k = i - 1; k >= 0; k--)
5189 nf_unregister_net_hook(net, &flowtable->ops[i]);
5190
5191 kfree(flowtable->ops);
5192err3:
5193 module_put(type->owner);
5194err2:
5195 kfree(flowtable->name);
5196err1:
5197 kfree(flowtable);
5198 return err;
5199}
5200
5201static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
5202 struct sk_buff *skb,
5203 const struct nlmsghdr *nlh,
5204 const struct nlattr * const nla[],
5205 struct netlink_ext_ack *extack)
5206{
5207 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
5208 u8 genmask = nft_genmask_next(net);
5209 int family = nfmsg->nfgen_family;
5210 struct nft_flowtable *flowtable;
5211 struct nft_af_info *afi;
5212 struct nft_table *table;
5213 struct nft_ctx ctx;
5214
5215 afi = nf_tables_afinfo_lookup(net, family, true);
5216 if (IS_ERR(afi))
5217 return PTR_ERR(afi);
5218
5219 table = nf_tables_table_lookup(afi, nla[NFTA_FLOWTABLE_TABLE], genmask);
5220 if (IS_ERR(table))
5221 return PTR_ERR(table);
5222
5223 flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
5224 genmask);
5225 if (IS_ERR(flowtable))
5226 return PTR_ERR(flowtable);
5227 if (flowtable->use > 0)
5228 return -EBUSY;
5229
5230 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
5231
5232 return nft_delflowtable(&ctx, flowtable);
5233}
5234
5235static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
5236 u32 portid, u32 seq, int event,
5237 u32 flags, int family,
5238 struct nft_flowtable *flowtable)
5239{
5240 struct nlattr *nest, *nest_devs;
5241 struct nfgenmsg *nfmsg;
5242 struct nlmsghdr *nlh;
5243 int i;
5244
5245 event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
5246 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
5247 if (nlh == NULL)
5248 goto nla_put_failure;
5249
5250 nfmsg = nlmsg_data(nlh);
5251 nfmsg->nfgen_family = family;
5252 nfmsg->version = NFNETLINK_V0;
5253 nfmsg->res_id = htons(net->nft.base_seq & 0xffff);
5254
5255 if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
5256 nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
5257 nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
5258 goto nla_put_failure;
5259
5260 nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);
5261 if (nla_put_be32(skb, NFTA_FLOWTABLE_HOOK_NUM, htonl(flowtable->hooknum)) ||
5262 nla_put_be32(skb, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(flowtable->priority)))
5263 goto nla_put_failure;
5264
5265 nest_devs = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK_DEVS);
5266 if (!nest_devs)
5267 goto nla_put_failure;
5268
5269 for (i = 0; i < flowtable->ops_len; i++) {
5270 if (flowtable->ops[i].dev &&
5271 nla_put_string(skb, NFTA_DEVICE_NAME,
5272 flowtable->ops[i].dev->name))
5273 goto nla_put_failure;
5274 }
5275 nla_nest_end(skb, nest_devs);
5276 nla_nest_end(skb, nest);
5277
5278 nlmsg_end(skb, nlh);
5279 return 0;
5280
5281nla_put_failure:
5282 nlmsg_trim(skb, nlh);
5283 return -1;
5284}
5285
5286struct nft_flowtable_filter {
5287 char *table;
5288};
5289
5290static int nf_tables_dump_flowtable(struct sk_buff *skb,
5291 struct netlink_callback *cb)
5292{
5293 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
5294 struct nft_flowtable_filter *filter = cb->data;
5295 unsigned int idx = 0, s_idx = cb->args[0];
5296 struct net *net = sock_net(skb->sk);
5297 int family = nfmsg->nfgen_family;
5298 struct nft_flowtable *flowtable;
5299 const struct nft_af_info *afi;
5300 const struct nft_table *table;
5301
5302 rcu_read_lock();
5303 cb->seq = net->nft.base_seq;
5304
5305 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
5306 if (family != NFPROTO_UNSPEC && family != afi->family)
5307 continue;
5308
5309 list_for_each_entry_rcu(table, &afi->tables, list) {
5310 list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
5311 if (!nft_is_active(net, flowtable))
5312 goto cont;
5313 if (idx < s_idx)
5314 goto cont;
5315 if (idx > s_idx)
5316 memset(&cb->args[1], 0,
5317 sizeof(cb->args) - sizeof(cb->args[0]));
5318 if (filter && filter->table[0] &&
5319 strcmp(filter->table, table->name))
5320 goto cont;
5321
5322 if (nf_tables_fill_flowtable_info(skb, net, NETLINK_CB(cb->skb).portid,
5323 cb->nlh->nlmsg_seq,
5324 NFT_MSG_NEWFLOWTABLE,
5325 NLM_F_MULTI | NLM_F_APPEND,
5326 afi->family, flowtable) < 0)
5327 goto done;
5328
5329 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
5330cont:
5331 idx++;
5332 }
5333 }
5334 }
5335done:
5336 rcu_read_unlock();
5337
5338 cb->args[0] = idx;
5339 return skb->len;
5340}
5341
5342static int nf_tables_dump_flowtable_done(struct netlink_callback *cb)
5343{
5344 struct nft_flowtable_filter *filter = cb->data;
5345
5346 if (!filter)
5347 return 0;
5348
5349 kfree(filter->table);
5350 kfree(filter);
5351
5352 return 0;
5353}
5354
5355static struct nft_flowtable_filter *
5356nft_flowtable_filter_alloc(const struct nlattr * const nla[])
5357{
5358 struct nft_flowtable_filter *filter;
5359
5360 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
5361 if (!filter)
5362 return ERR_PTR(-ENOMEM);
5363
5364 if (nla[NFTA_FLOWTABLE_TABLE]) {
5365 filter->table = nla_strdup(nla[NFTA_FLOWTABLE_TABLE],
5366 GFP_KERNEL);
5367 if (!filter->table) {
5368 kfree(filter);
5369 return ERR_PTR(-ENOMEM);
5370 }
5371 }
5372 return filter;
5373}
5374
5375static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
5376 struct sk_buff *skb,
5377 const struct nlmsghdr *nlh,
5378 const struct nlattr * const nla[],
5379 struct netlink_ext_ack *extack)
5380{
5381 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
5382 u8 genmask = nft_genmask_cur(net);
5383 int family = nfmsg->nfgen_family;
5384 struct nft_flowtable *flowtable;
5385 const struct nft_af_info *afi;
5386 const struct nft_table *table;
5387 struct sk_buff *skb2;
5388 int err;
5389
5390 if (nlh->nlmsg_flags & NLM_F_DUMP) {
5391 struct netlink_dump_control c = {
5392 .dump = nf_tables_dump_flowtable,
5393 .done = nf_tables_dump_flowtable_done,
5394 };
5395
5396 if (nla[NFTA_FLOWTABLE_TABLE]) {
5397 struct nft_flowtable_filter *filter;
5398
5399 filter = nft_flowtable_filter_alloc(nla);
5400 if (IS_ERR(filter))
5401 return -ENOMEM;
5402
5403 c.data = filter;
5404 }
5405 return netlink_dump_start(nlsk, skb, nlh, &c);
5406 }
5407
5408 if (!nla[NFTA_FLOWTABLE_NAME])
5409 return -EINVAL;
5410
5411 afi = nf_tables_afinfo_lookup(net, family, false);
5412 if (IS_ERR(afi))
5413 return PTR_ERR(afi);
5414
5415 table = nf_tables_table_lookup(afi, nla[NFTA_FLOWTABLE_TABLE], genmask);
5416 if (IS_ERR(table))
5417 return PTR_ERR(table);
5418
5419 flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
5420 genmask);
5421 if (IS_ERR(table))
5422 return PTR_ERR(flowtable);
5423
5424 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
5425 if (!skb2)
5426 return -ENOMEM;
5427
5428 err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid,
5429 nlh->nlmsg_seq,
5430 NFT_MSG_NEWFLOWTABLE, 0, family,
5431 flowtable);
5432 if (err < 0)
5433 goto err;
5434
5435 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
5436err:
5437 kfree_skb(skb2);
5438 return err;
5439}
5440
5441static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
5442 struct nft_flowtable *flowtable,
5443 int event)
5444{
5445 struct sk_buff *skb;
5446 int err;
5447
5448 if (ctx->report &&
5449 !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
5450 return;
5451
5452 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
5453 if (skb == NULL)
5454 goto err;
5455
5456 err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid,
5457 ctx->seq, event, 0,
5458 ctx->afi->family, flowtable);
5459 if (err < 0) {
5460 kfree_skb(skb);
5461 goto err;
5462 }
5463
5464 nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
5465 ctx->report, GFP_KERNEL);
5466 return;
5467err:
5468 nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
5469}
5470
5471static void nft_flowtable_destroy(void *ptr, void *arg)
5472{
5473 kfree(ptr);
5474}
5475
5476static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
5477{
5478 cancel_delayed_work_sync(&flowtable->data.gc_work);
5479 kfree(flowtable->name);
5480 rhashtable_free_and_destroy(&flowtable->data.rhashtable,
5481 nft_flowtable_destroy, NULL);
5482 module_put(flowtable->data.type->owner);
5483}
5484
4842static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net, 5485static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
4843 u32 portid, u32 seq) 5486 u32 portid, u32 seq)
4844{ 5487{
@@ -4869,6 +5512,49 @@ nla_put_failure:
4869 return -EMSGSIZE; 5512 return -EMSGSIZE;
4870} 5513}
4871 5514
5515static void nft_flowtable_event(unsigned long event, struct net_device *dev,
5516 struct nft_flowtable *flowtable)
5517{
5518 int i;
5519
5520 for (i = 0; i < flowtable->ops_len; i++) {
5521 if (flowtable->ops[i].dev != dev)
5522 continue;
5523
5524 nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]);
5525 flowtable->ops[i].dev = NULL;
5526 break;
5527 }
5528}
5529
5530static int nf_tables_flowtable_event(struct notifier_block *this,
5531 unsigned long event, void *ptr)
5532{
5533 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
5534 struct nft_flowtable *flowtable;
5535 struct nft_table *table;
5536 struct nft_af_info *afi;
5537
5538 if (event != NETDEV_UNREGISTER)
5539 return 0;
5540
5541 nfnl_lock(NFNL_SUBSYS_NFTABLES);
5542 list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
5543 list_for_each_entry(table, &afi->tables, list) {
5544 list_for_each_entry(flowtable, &table->flowtables, list) {
5545 nft_flowtable_event(event, dev, flowtable);
5546 }
5547 }
5548 }
5549 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
5550
5551 return NOTIFY_DONE;
5552}
5553
5554static struct notifier_block nf_tables_flowtable_notifier = {
5555 .notifier_call = nf_tables_flowtable_event,
5556};
5557
4872static void nf_tables_gen_notify(struct net *net, struct sk_buff *skb, 5558static void nf_tables_gen_notify(struct net *net, struct sk_buff *skb,
4873 int event) 5559 int event)
4874{ 5560{
@@ -5021,6 +5707,21 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
5021 .attr_count = NFTA_OBJ_MAX, 5707 .attr_count = NFTA_OBJ_MAX,
5022 .policy = nft_obj_policy, 5708 .policy = nft_obj_policy,
5023 }, 5709 },
5710 [NFT_MSG_NEWFLOWTABLE] = {
5711 .call_batch = nf_tables_newflowtable,
5712 .attr_count = NFTA_FLOWTABLE_MAX,
5713 .policy = nft_flowtable_policy,
5714 },
5715 [NFT_MSG_GETFLOWTABLE] = {
5716 .call = nf_tables_getflowtable,
5717 .attr_count = NFTA_FLOWTABLE_MAX,
5718 .policy = nft_flowtable_policy,
5719 },
5720 [NFT_MSG_DELFLOWTABLE] = {
5721 .call_batch = nf_tables_delflowtable,
5722 .attr_count = NFTA_FLOWTABLE_MAX,
5723 .policy = nft_flowtable_policy,
5724 },
5024}; 5725};
5025 5726
5026static void nft_chain_commit_update(struct nft_trans *trans) 5727static void nft_chain_commit_update(struct nft_trans *trans)
@@ -5066,6 +5767,9 @@ static void nf_tables_commit_release(struct nft_trans *trans)
5066 case NFT_MSG_DELOBJ: 5767 case NFT_MSG_DELOBJ:
5067 nft_obj_destroy(nft_trans_obj(trans)); 5768 nft_obj_destroy(nft_trans_obj(trans));
5068 break; 5769 break;
5770 case NFT_MSG_DELFLOWTABLE:
5771 nf_tables_flowtable_destroy(nft_trans_flowtable(trans));
5772 break;
5069 } 5773 }
5070 kfree(trans); 5774 kfree(trans);
5071} 5775}
@@ -5183,6 +5887,21 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
5183 nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans), 5887 nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
5184 NFT_MSG_DELOBJ); 5888 NFT_MSG_DELOBJ);
5185 break; 5889 break;
5890 case NFT_MSG_NEWFLOWTABLE:
5891 nft_clear(net, nft_trans_flowtable(trans));
5892 nf_tables_flowtable_notify(&trans->ctx,
5893 nft_trans_flowtable(trans),
5894 NFT_MSG_NEWFLOWTABLE);
5895 nft_trans_destroy(trans);
5896 break;
5897 case NFT_MSG_DELFLOWTABLE:
5898 list_del_rcu(&nft_trans_flowtable(trans)->list);
5899 nf_tables_flowtable_notify(&trans->ctx,
5900 nft_trans_flowtable(trans),
5901 NFT_MSG_DELFLOWTABLE);
5902 nft_unregister_flowtable_net_hooks(net,
5903 nft_trans_flowtable(trans));
5904 break;
5186 } 5905 }
5187 } 5906 }
5188 5907
@@ -5220,6 +5939,9 @@ static void nf_tables_abort_release(struct nft_trans *trans)
5220 case NFT_MSG_NEWOBJ: 5939 case NFT_MSG_NEWOBJ:
5221 nft_obj_destroy(nft_trans_obj(trans)); 5940 nft_obj_destroy(nft_trans_obj(trans));
5222 break; 5941 break;
5942 case NFT_MSG_NEWFLOWTABLE:
5943 nf_tables_flowtable_destroy(nft_trans_flowtable(trans));
5944 break;
5223 } 5945 }
5224 kfree(trans); 5946 kfree(trans);
5225} 5947}
@@ -5309,6 +6031,17 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
5309 nft_clear(trans->ctx.net, nft_trans_obj(trans)); 6031 nft_clear(trans->ctx.net, nft_trans_obj(trans));
5310 nft_trans_destroy(trans); 6032 nft_trans_destroy(trans);
5311 break; 6033 break;
6034 case NFT_MSG_NEWFLOWTABLE:
6035 trans->ctx.table->use--;
6036 list_del_rcu(&nft_trans_flowtable(trans)->list);
6037 nft_unregister_flowtable_net_hooks(net,
6038 nft_trans_flowtable(trans));
6039 break;
6040 case NFT_MSG_DELFLOWTABLE:
6041 trans->ctx.table->use++;
6042 nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
6043 nft_trans_destroy(trans);
6044 break;
5312 } 6045 }
5313 } 6046 }
5314 6047
@@ -5865,6 +6598,7 @@ EXPORT_SYMBOL_GPL(__nft_release_basechain);
5865/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */ 6598/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
5866static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) 6599static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
5867{ 6600{
6601 struct nft_flowtable *flowtable, *nf;
5868 struct nft_table *table, *nt; 6602 struct nft_table *table, *nt;
5869 struct nft_chain *chain, *nc; 6603 struct nft_chain *chain, *nc;
5870 struct nft_object *obj, *ne; 6604 struct nft_object *obj, *ne;
@@ -5878,6 +6612,9 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
5878 list_for_each_entry_safe(table, nt, &afi->tables, list) { 6612 list_for_each_entry_safe(table, nt, &afi->tables, list) {
5879 list_for_each_entry(chain, &table->chains, list) 6613 list_for_each_entry(chain, &table->chains, list)
5880 nf_tables_unregister_hook(net, table, chain); 6614 nf_tables_unregister_hook(net, table, chain);
6615 list_for_each_entry(flowtable, &table->flowtables, list)
6616 nf_unregister_net_hooks(net, flowtable->ops,
6617 flowtable->ops_len);
5881 /* No packets are walking on these chains anymore. */ 6618 /* No packets are walking on these chains anymore. */
5882 ctx.table = table; 6619 ctx.table = table;
5883 list_for_each_entry(chain, &table->chains, list) { 6620 list_for_each_entry(chain, &table->chains, list) {
@@ -5888,6 +6625,11 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
5888 nf_tables_rule_destroy(&ctx, rule); 6625 nf_tables_rule_destroy(&ctx, rule);
5889 } 6626 }
5890 } 6627 }
6628 list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
6629 list_del(&flowtable->list);
6630 table->use--;
6631 nf_tables_flowtable_destroy(flowtable);
6632 }
5891 list_for_each_entry_safe(set, ns, &table->sets, list) { 6633 list_for_each_entry_safe(set, ns, &table->sets, list) {
5892 list_del(&set->list); 6634 list_del(&set->list);
5893 table->use--; 6635 table->use--;
@@ -5932,6 +6674,8 @@ static int __init nf_tables_module_init(void)
5932 if (err < 0) 6674 if (err < 0)
5933 goto err3; 6675 goto err3;
5934 6676
6677 register_netdevice_notifier(&nf_tables_flowtable_notifier);
6678
5935 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n"); 6679 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
5936 return register_pernet_subsys(&nf_tables_net_ops); 6680 return register_pernet_subsys(&nf_tables_net_ops);
5937err3: 6681err3:
@@ -5946,6 +6690,7 @@ static void __exit nf_tables_module_exit(void)
5946{ 6690{
5947 unregister_pernet_subsys(&nf_tables_net_ops); 6691 unregister_pernet_subsys(&nf_tables_net_ops);
5948 nfnetlink_subsys_unregister(&nf_tables_subsys); 6692 nfnetlink_subsys_unregister(&nf_tables_subsys);
6693 unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
5949 rcu_barrier(); 6694 rcu_barrier();
5950 nf_tables_core_module_exit(); 6695 nf_tables_core_module_exit();
5951 kfree(info); 6696 kfree(info);