From 103335644265d96c656a7de3d5994fbd11246300 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 5 Feb 2018 13:35:24 +0100 Subject: kernel: backport netfilter NAT offload support to 4.14 This only works with nftables for now, iptables support will be added later. Includes a number of related upstream nftables improvements to simplify backporting follow-up changes Signed-off-by: John Crispin Signed-off-by: Felix Fietkau --- ...f_flow_table-move-init-code-to-nf_flow_ta.patch | 298 +++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 target/linux/generic/backport-4.14/357-netfilter-nf_flow_table-move-init-code-to-nf_flow_ta.patch (limited to 'target/linux/generic/backport-4.14/357-netfilter-nf_flow_table-move-init-code-to-nf_flow_ta.patch') diff --git a/target/linux/generic/backport-4.14/357-netfilter-nf_flow_table-move-init-code-to-nf_flow_ta.patch b/target/linux/generic/backport-4.14/357-netfilter-nf_flow_table-move-init-code-to-nf_flow_ta.patch new file mode 100644 index 0000000000..75cbda6baf --- /dev/null +++ b/target/linux/generic/backport-4.14/357-netfilter-nf_flow_table-move-init-code-to-nf_flow_ta.patch @@ -0,0 +1,298 @@ +From: Felix Fietkau +Date: Sun, 18 Feb 2018 18:16:31 +0100 +Subject: [PATCH] netfilter: nf_flow_table: move init code to + nf_flow_table_core.c + +Reduces duplication of .gc and .params in flowtable type definitions and +makes the API clearer + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -14,9 +14,8 @@ struct nf_flowtable; + struct nf_flowtable_type { + struct list_head list; + int family; +- void (*gc)(struct work_struct *work); ++ int (*init)(struct nf_flowtable *ft); + void (*free)(struct nf_flowtable *ft); +- const struct rhashtable_params *params; + nf_hookfn *hook; + struct module *owner; + }; +@@ -100,9 +99,8 @@ int nf_flow_table_iterate(struct nf_flow + + void nf_flow_table_cleanup(struct net *net, struct net_device *dev); + ++int nf_flow_table_init(struct nf_flowtable *flow_table); + void nf_flow_table_free(struct nf_flowtable *flow_table); +-void nf_flow_offload_work_gc(struct work_struct *work); +-extern const struct rhashtable_params nf_flow_offload_rhash_params; + + void flow_offload_dead(struct flow_offload *flow); + +--- a/net/ipv4/netfilter/nf_flow_table_ipv4.c ++++ b/net/ipv4/netfilter/nf_flow_table_ipv4.c +@@ -7,8 +7,7 @@ + + static struct nf_flowtable_type flowtable_ipv4 = { + .family = NFPROTO_IPV4, +- .params = &nf_flow_offload_rhash_params, +- .gc = nf_flow_offload_work_gc, ++ .init = nf_flow_table_init, + .free = nf_flow_table_free, + .hook = nf_flow_offload_ip_hook, + .owner = THIS_MODULE, +--- a/net/ipv6/netfilter/nf_flow_table_ipv6.c ++++ b/net/ipv6/netfilter/nf_flow_table_ipv6.c +@@ -8,8 +8,7 @@ + + static struct nf_flowtable_type flowtable_ipv6 = { + .family = NFPROTO_IPV6, +- .params = &nf_flow_offload_rhash_params, +- .gc = nf_flow_offload_work_gc, ++ .init = nf_flow_table_init, + .free = nf_flow_table_free, + .hook = nf_flow_offload_ipv6_hook, + .owner = THIS_MODULE, +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -116,16 +116,50 @@ void flow_offload_dead(struct flow_offlo + } + EXPORT_SYMBOL_GPL(flow_offload_dead); + ++static u32 flow_offload_hash(const void *data, u32 len, u32 seed) ++{ ++ const struct flow_offload_tuple *tuple = data; ++ ++ return jhash(tuple, offsetof(struct flow_offload_tuple, dir), seed); ++} ++ ++static u32 flow_offload_hash_obj(const void *data, u32 len, u32 seed) ++{ ++ const struct flow_offload_tuple_rhash *tuplehash = data; ++ ++ return jhash(&tuplehash->tuple, offsetof(struct flow_offload_tuple, dir), seed); ++} ++ ++static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg, ++ const void *ptr) ++{ ++ const struct flow_offload_tuple *tuple = arg->key; ++ const struct flow_offload_tuple_rhash *x = ptr; ++ ++ if (memcmp(&x->tuple, tuple, offsetof(struct flow_offload_tuple, dir))) ++ return 1; ++ ++ return 0; ++} ++ ++static const struct rhashtable_params nf_flow_offload_rhash_params = { ++ .head_offset = offsetof(struct flow_offload_tuple_rhash, node), ++ .hashfn = flow_offload_hash, ++ .obj_hashfn = flow_offload_hash_obj, ++ .obj_cmpfn = flow_offload_hash_cmp, ++ .automatic_shrinking = true, ++}; ++ + int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) + { + flow->timeout = (u32)jiffies; + + rhashtable_insert_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, +- *flow_table->type->params); ++ nf_flow_offload_rhash_params); + rhashtable_insert_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, +- *flow_table->type->params); ++ nf_flow_offload_rhash_params); + return 0; + } + EXPORT_SYMBOL_GPL(flow_offload_add); +@@ -135,10 +169,10 @@ static void flow_offload_del(struct nf_f + { + rhashtable_remove_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, +- *flow_table->type->params); ++ nf_flow_offload_rhash_params); + rhashtable_remove_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, +- *flow_table->type->params); ++ nf_flow_offload_rhash_params); + + flow_offload_free(flow); + } +@@ -148,7 +182,7 @@ flow_offload_lookup(struct nf_flowtable + struct flow_offload_tuple *tuple) + { + return rhashtable_lookup_fast(&flow_table->rhashtable, tuple, +- *flow_table->type->params); ++ nf_flow_offload_rhash_params); + } + EXPORT_SYMBOL_GPL(flow_offload_lookup); + +@@ -237,7 +271,7 @@ out: + return 1; + } + +-void nf_flow_offload_work_gc(struct work_struct *work) ++static void nf_flow_offload_work_gc(struct work_struct *work) + { + struct nf_flowtable *flow_table; + +@@ -245,42 +279,6 @@ void nf_flow_offload_work_gc(struct work + nf_flow_offload_gc_step(flow_table); + queue_delayed_work(system_power_efficient_wq, &flow_table->gc_work, HZ); + } +-EXPORT_SYMBOL_GPL(nf_flow_offload_work_gc); +- +-static u32 flow_offload_hash(const void *data, u32 len, u32 seed) +-{ +- const struct flow_offload_tuple *tuple = data; +- +- return jhash(tuple, offsetof(struct flow_offload_tuple, dir), seed); +-} +- +-static u32 flow_offload_hash_obj(const void *data, u32 len, u32 seed) +-{ +- const struct flow_offload_tuple_rhash *tuplehash = data; +- +- return jhash(&tuplehash->tuple, offsetof(struct flow_offload_tuple, dir), seed); +-} +- +-static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg, +- const void *ptr) +-{ +- const struct flow_offload_tuple *tuple = arg->key; +- const struct flow_offload_tuple_rhash *x = ptr; +- +- if (memcmp(&x->tuple, tuple, offsetof(struct flow_offload_tuple, dir))) +- return 1; +- +- return 0; +-} +- +-const struct rhashtable_params nf_flow_offload_rhash_params = { +- .head_offset = offsetof(struct flow_offload_tuple_rhash, node), +- .hashfn = flow_offload_hash, +- .obj_hashfn = flow_offload_hash_obj, +- .obj_cmpfn = flow_offload_hash_cmp, +- .automatic_shrinking = true, +-}; +-EXPORT_SYMBOL_GPL(nf_flow_offload_rhash_params); + + static int nf_flow_nat_port_tcp(struct sk_buff *skb, unsigned int thoff, + __be16 port, __be16 new_port) +@@ -398,6 +396,24 @@ int nf_flow_dnat_port(const struct flow_ + } + EXPORT_SYMBOL_GPL(nf_flow_dnat_port); + ++int nf_flow_table_init(struct nf_flowtable *flowtable) ++{ ++ int err; ++ ++ INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc); ++ ++ err = rhashtable_init(&flowtable->rhashtable, ++ &nf_flow_offload_rhash_params); ++ if (err < 0) ++ return err; ++ ++ queue_delayed_work(system_power_efficient_wq, ++ &flowtable->gc_work, HZ); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nf_flow_table_init); ++ + static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data) + { + struct net_device *dev = data; +@@ -423,8 +439,10 @@ EXPORT_SYMBOL_GPL(nf_flow_table_cleanup) + + void nf_flow_table_free(struct nf_flowtable *flow_table) + { ++ cancel_delayed_work_sync(&flow_table->gc_work); + nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); + WARN_ON(!nf_flow_offload_gc_step(flow_table)); ++ rhashtable_destroy(&flow_table->rhashtable); + } + EXPORT_SYMBOL_GPL(nf_flow_table_free); + +--- a/net/netfilter/nf_flow_table_inet.c ++++ b/net/netfilter/nf_flow_table_inet.c +@@ -22,8 +22,7 @@ nf_flow_offload_inet_hook(void *priv, st + + static struct nf_flowtable_type flowtable_inet = { + .family = NFPROTO_INET, +- .params = &nf_flow_offload_rhash_params, +- .gc = nf_flow_offload_work_gc, ++ .init = nf_flow_table_init, + .free = nf_flow_table_free, + .hook = nf_flow_offload_inet_hook, + .owner = THIS_MODULE, +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5013,40 +5013,38 @@ static int nf_tables_newflowtable(struct + } + + flowtable->data.type = type; +- err = rhashtable_init(&flowtable->data.rhashtable, type->params); ++ err = type->init(&flowtable->data); + if (err < 0) + goto err3; + + err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK], + flowtable); + if (err < 0) +- goto err3; ++ goto err4; + + for (i = 0; i < flowtable->ops_len; i++) { + err = nf_register_net_hook(net, &flowtable->ops[i]); + if (err < 0) +- goto err4; ++ goto err5; + } + + err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable); + if (err < 0) +- goto err5; +- +- INIT_DEFERRABLE_WORK(&flowtable->data.gc_work, type->gc); +- queue_delayed_work(system_power_efficient_wq, +- &flowtable->data.gc_work, HZ); ++ goto err6; + + list_add_tail_rcu(&flowtable->list, &table->flowtables); + table->use++; + + return 0; +-err5: ++err6: + i = flowtable->ops_len; +-err4: ++err5: + for (k = i - 1; k >= 0; k--) + nf_unregister_net_hook(net, &flowtable->ops[i]); + + kfree(flowtable->ops); ++err4: ++ flowtable->data.type->free(&flowtable->data); + err3: + module_put(type->owner); + err2: +@@ -5325,10 +5323,8 @@ err: + + static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) + { +- cancel_delayed_work_sync(&flowtable->data.gc_work); + kfree(flowtable->name); + flowtable->data.type->free(&flowtable->data); +- rhashtable_destroy(&flowtable->data.rhashtable); + module_put(flowtable->data.type->owner); + } + -- cgit v1.2.3