diff options
author | Adrian Schmutzler <freifunk@adrianschmutzler.de> | 2020-08-07 14:29:11 +0200 |
---|---|---|
committer | Adrian Schmutzler <freifunk@adrianschmutzler.de> | 2020-09-02 16:29:23 +0200 |
commit | 95acc4fe0e31ae91d485635c021d259e06785b5d (patch) | |
tree | aa079a7cb0e09c4f2ba655925095fc27186c27a9 /target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch | |
parent | 66ab1fb395f85e018cb1c6ae0d3a14aa46373f84 (diff) | |
download | upstream-95acc4fe0e31ae91d485635c021d259e06785b5d.tar.gz upstream-95acc4fe0e31ae91d485635c021d259e06785b5d.tar.bz2 upstream-95acc4fe0e31ae91d485635c021d259e06785b5d.zip |
kernel: remove support for kernel 4.14
No target uses kernel 4.14 anymore.
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
Diffstat (limited to 'target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch')
-rw-r--r-- | target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch | 952 |
1 files changed, 0 insertions, 952 deletions
diff --git a/target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch b/target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch deleted file mode 100644 index 5df56dd643..0000000000 --- a/target/linux/generic/backport-4.14/352-v4.18-netfilter-nf_flow_table-rename-nf_flow_table.c-to-nf.patch +++ /dev/null @@ -1,952 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Fri, 16 Feb 2018 11:08:47 +0100 -Subject: [PATCH] netfilter: nf_flow_table: rename nf_flow_table.c to - nf_flow_table_core.c - -Preparation for adding more code to the same module - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - rename net/netfilter/{nf_flow_table.c => nf_flow_table_core.c} (100%) - ---- a/net/netfilter/Makefile -+++ b/net/netfilter/Makefile -@@ -113,6 +113,8 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_ - - # flow table infrastructure - obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o -+nf_flow_table-objs := nf_flow_table_core.o -+ - obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o - - # generic X tables ---- a/net/netfilter/nf_flow_table.c -+++ /dev/null -@@ -1,462 +0,0 @@ --#include <linux/kernel.h> --#include <linux/init.h> --#include <linux/module.h> --#include <linux/netfilter.h> --#include <linux/rhashtable.h> --#include <linux/netdevice.h> --#include <net/ip.h> --#include <net/ip6_route.h> --#include <net/netfilter/nf_tables.h> --#include <net/netfilter/nf_flow_table.h> --#include <net/netfilter/nf_conntrack.h> --#include <net/netfilter/nf_conntrack_core.h> --#include <net/netfilter/nf_conntrack_tuple.h> -- --struct flow_offload_entry { -- struct flow_offload flow; -- struct nf_conn *ct; -- struct rcu_head rcu_head; --}; -- --static void --flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, -- struct nf_flow_route *route, -- enum flow_offload_tuple_dir dir) --{ -- struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; -- struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; -- struct dst_entry *dst = route->tuple[dir].dst; -- -- ft->dir = dir; -- -- switch (ctt->src.l3num) { -- case NFPROTO_IPV4: -- ft->src_v4 = ctt->src.u3.in; -- ft->dst_v4 = ctt->dst.u3.in; -- ft->mtu = ip_dst_mtu_maybe_forward(dst, true); -- break; -- case NFPROTO_IPV6: -- ft->src_v6 = ctt->src.u3.in6; -- ft->dst_v6 = ctt->dst.u3.in6; -- ft->mtu = ip6_dst_mtu_forward(dst); -- break; -- } -- -- ft->l3proto = ctt->src.l3num; -- ft->l4proto = ctt->dst.protonum; -- ft->src_port = ctt->src.u.tcp.port; -- ft->dst_port = ctt->dst.u.tcp.port; -- -- ft->iifidx = route->tuple[dir].ifindex; -- ft->oifidx = route->tuple[!dir].ifindex; -- ft->dst_cache = dst; --} -- --struct flow_offload * --flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route) --{ -- struct flow_offload_entry *entry; -- struct flow_offload *flow; -- -- if (unlikely(nf_ct_is_dying(ct) || -- !atomic_inc_not_zero(&ct->ct_general.use))) -- return NULL; -- -- entry = kzalloc(sizeof(*entry), GFP_ATOMIC); -- if (!entry) -- goto err_ct_refcnt; -- -- flow = &entry->flow; -- -- if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst)) -- goto err_dst_cache_original; -- -- if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst)) -- goto err_dst_cache_reply; -- -- entry->ct = ct; -- -- flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_ORIGINAL); -- flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_REPLY); -- -- if (ct->status & IPS_SRC_NAT) -- flow->flags |= FLOW_OFFLOAD_SNAT; -- else if (ct->status & IPS_DST_NAT) -- flow->flags |= FLOW_OFFLOAD_DNAT; -- -- return flow; -- --err_dst_cache_reply: -- dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst); --err_dst_cache_original: -- kfree(entry); --err_ct_refcnt: -- nf_ct_put(ct); -- -- return NULL; --} --EXPORT_SYMBOL_GPL(flow_offload_alloc); -- --void flow_offload_free(struct flow_offload *flow) --{ -- struct flow_offload_entry *e; -- -- dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache); -- dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache); -- e = container_of(flow, struct flow_offload_entry, flow); -- nf_ct_delete(e->ct, 0, 0); -- nf_ct_put(e->ct); -- kfree_rcu(e, rcu_head); --} --EXPORT_SYMBOL_GPL(flow_offload_free); -- --void flow_offload_dead(struct flow_offload *flow) --{ -- flow->flags |= FLOW_OFFLOAD_DYING; --} --EXPORT_SYMBOL_GPL(flow_offload_dead); -- --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); -- rhashtable_insert_fast(&flow_table->rhashtable, -- &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, -- *flow_table->type->params); -- return 0; --} --EXPORT_SYMBOL_GPL(flow_offload_add); -- --static void flow_offload_del(struct nf_flowtable *flow_table, -- struct flow_offload *flow) --{ -- rhashtable_remove_fast(&flow_table->rhashtable, -- &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, -- *flow_table->type->params); -- rhashtable_remove_fast(&flow_table->rhashtable, -- &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, -- *flow_table->type->params); -- -- flow_offload_free(flow); --} -- --struct flow_offload_tuple_rhash * --flow_offload_lookup(struct nf_flowtable *flow_table, -- struct flow_offload_tuple *tuple) --{ -- return rhashtable_lookup_fast(&flow_table->rhashtable, tuple, -- *flow_table->type->params); --} --EXPORT_SYMBOL_GPL(flow_offload_lookup); -- --int nf_flow_table_iterate(struct nf_flowtable *flow_table, -- void (*iter)(struct flow_offload *flow, void *data), -- void *data) --{ -- struct flow_offload_tuple_rhash *tuplehash; -- struct rhashtable_iter hti; -- struct flow_offload *flow; -- int err; -- -- err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); -- if (err) -- return err; -- -- rhashtable_walk_start(&hti); -- -- while ((tuplehash = rhashtable_walk_next(&hti))) { -- if (IS_ERR(tuplehash)) { -- err = PTR_ERR(tuplehash); -- if (err != -EAGAIN) -- goto out; -- -- continue; -- } -- if (tuplehash->tuple.dir) -- continue; -- -- flow = container_of(tuplehash, struct flow_offload, tuplehash[0]); -- -- iter(flow, data); -- } --out: -- rhashtable_walk_stop(&hti); -- rhashtable_walk_exit(&hti); -- -- return err; --} --EXPORT_SYMBOL_GPL(nf_flow_table_iterate); -- --static inline bool nf_flow_has_expired(const struct flow_offload *flow) --{ -- return (__s32)(flow->timeout - (u32)jiffies) <= 0; --} -- --static inline bool nf_flow_is_dying(const struct flow_offload *flow) --{ -- return flow->flags & FLOW_OFFLOAD_DYING; --} -- --static int nf_flow_offload_gc_step(struct nf_flowtable *flow_table) --{ -- struct flow_offload_tuple_rhash *tuplehash; -- struct rhashtable_iter hti; -- struct flow_offload *flow; -- int err; -- -- err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); -- if (err) -- return 0; -- -- rhashtable_walk_start(&hti); -- -- while ((tuplehash = rhashtable_walk_next(&hti))) { -- if (IS_ERR(tuplehash)) { -- err = PTR_ERR(tuplehash); -- if (err != -EAGAIN) -- goto out; -- -- continue; -- } -- if (tuplehash->tuple.dir) -- continue; -- -- flow = container_of(tuplehash, struct flow_offload, tuplehash[0]); -- -- if (nf_flow_has_expired(flow) || -- nf_flow_is_dying(flow)) -- flow_offload_del(flow_table, flow); -- } --out: -- rhashtable_walk_stop(&hti); -- rhashtable_walk_exit(&hti); -- -- return 1; --} -- --void nf_flow_offload_work_gc(struct work_struct *work) --{ -- struct nf_flowtable *flow_table; -- -- flow_table = container_of(work, struct nf_flowtable, gc_work.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) --{ -- struct tcphdr *tcph; -- -- if (!pskb_may_pull(skb, thoff + sizeof(*tcph)) || -- skb_try_make_writable(skb, thoff + sizeof(*tcph))) -- return -1; -- -- tcph = (void *)(skb_network_header(skb) + thoff); -- inet_proto_csum_replace2(&tcph->check, skb, port, new_port, true); -- -- return 0; --} -- --static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff, -- __be16 port, __be16 new_port) --{ -- struct udphdr *udph; -- -- if (!pskb_may_pull(skb, thoff + sizeof(*udph)) || -- skb_try_make_writable(skb, thoff + sizeof(*udph))) -- return -1; -- -- udph = (void *)(skb_network_header(skb) + thoff); -- if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { -- inet_proto_csum_replace2(&udph->check, skb, port, -- new_port, true); -- if (!udph->check) -- udph->check = CSUM_MANGLED_0; -- } -- -- return 0; --} -- --static int nf_flow_nat_port(struct sk_buff *skb, unsigned int thoff, -- u8 protocol, __be16 port, __be16 new_port) --{ -- switch (protocol) { -- case IPPROTO_TCP: -- if (nf_flow_nat_port_tcp(skb, thoff, port, new_port) < 0) -- return NF_DROP; -- break; -- case IPPROTO_UDP: -- if (nf_flow_nat_port_udp(skb, thoff, port, new_port) < 0) -- return NF_DROP; -- break; -- } -- -- return 0; --} -- --int nf_flow_snat_port(const struct flow_offload *flow, -- struct sk_buff *skb, unsigned int thoff, -- u8 protocol, enum flow_offload_tuple_dir dir) --{ -- struct flow_ports *hdr; -- __be16 port, new_port; -- -- if (!pskb_may_pull(skb, thoff + sizeof(*hdr)) || -- skb_try_make_writable(skb, thoff + sizeof(*hdr))) -- return -1; -- -- hdr = (void *)(skb_network_header(skb) + thoff); -- -- switch (dir) { -- case FLOW_OFFLOAD_DIR_ORIGINAL: -- port = hdr->source; -- new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port; -- hdr->source = new_port; -- break; -- case FLOW_OFFLOAD_DIR_REPLY: -- port = hdr->dest; -- new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port; -- hdr->dest = new_port; -- break; -- default: -- return -1; -- } -- -- return nf_flow_nat_port(skb, thoff, protocol, port, new_port); --} --EXPORT_SYMBOL_GPL(nf_flow_snat_port); -- --int nf_flow_dnat_port(const struct flow_offload *flow, -- struct sk_buff *skb, unsigned int thoff, -- u8 protocol, enum flow_offload_tuple_dir dir) --{ -- struct flow_ports *hdr; -- __be16 port, new_port; -- -- if (!pskb_may_pull(skb, thoff + sizeof(*hdr)) || -- skb_try_make_writable(skb, thoff + sizeof(*hdr))) -- return -1; -- -- hdr = (void *)(skb_network_header(skb) + thoff); -- -- switch (dir) { -- case FLOW_OFFLOAD_DIR_ORIGINAL: -- port = hdr->dest; -- new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port; -- hdr->dest = new_port; -- break; -- case FLOW_OFFLOAD_DIR_REPLY: -- port = hdr->source; -- new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port; -- hdr->source = new_port; -- break; -- default: -- return -1; -- } -- -- return nf_flow_nat_port(skb, thoff, protocol, port, new_port); --} --EXPORT_SYMBOL_GPL(nf_flow_dnat_port); -- --static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data) --{ -- struct net_device *dev = data; -- -- if (dev && flow->tuplehash[0].tuple.iifidx != dev->ifindex) -- return; -- -- flow_offload_dead(flow); --} -- --static void nf_flow_table_iterate_cleanup(struct nf_flowtable *flowtable, -- void *data) --{ -- nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, data); -- flush_delayed_work(&flowtable->gc_work); --} -- --void nf_flow_table_cleanup(struct net *net, struct net_device *dev) --{ -- nft_flow_table_iterate(net, nf_flow_table_iterate_cleanup, dev); --} --EXPORT_SYMBOL_GPL(nf_flow_table_cleanup); -- --void nf_flow_table_free(struct nf_flowtable *flow_table) --{ -- nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); -- WARN_ON(!nf_flow_offload_gc_step(flow_table)); --} --EXPORT_SYMBOL_GPL(nf_flow_table_free); -- --static int nf_flow_table_netdev_event(struct notifier_block *this, -- unsigned long event, void *ptr) --{ -- struct net_device *dev = netdev_notifier_info_to_dev(ptr); -- -- if (event != NETDEV_DOWN) -- return NOTIFY_DONE; -- -- nf_flow_table_cleanup(dev_net(dev), dev); -- -- return NOTIFY_DONE; --} -- --static struct notifier_block flow_offload_netdev_notifier = { -- .notifier_call = nf_flow_table_netdev_event, --}; -- --static int __init nf_flow_table_module_init(void) --{ -- return register_netdevice_notifier(&flow_offload_netdev_notifier); --} -- --static void __exit nf_flow_table_module_exit(void) --{ -- unregister_netdevice_notifier(&flow_offload_netdev_notifier); --} -- --module_init(nf_flow_table_module_init); --module_exit(nf_flow_table_module_exit); -- --MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); ---- /dev/null -+++ b/net/netfilter/nf_flow_table_core.c -@@ -0,0 +1,462 @@ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/netfilter.h> -+#include <linux/rhashtable.h> -+#include <linux/netdevice.h> -+#include <net/ip.h> -+#include <net/ip6_route.h> -+#include <net/netfilter/nf_tables.h> -+#include <net/netfilter/nf_flow_table.h> -+#include <net/netfilter/nf_conntrack.h> -+#include <net/netfilter/nf_conntrack_core.h> -+#include <net/netfilter/nf_conntrack_tuple.h> -+ -+struct flow_offload_entry { -+ struct flow_offload flow; -+ struct nf_conn *ct; -+ struct rcu_head rcu_head; -+}; -+ -+static void -+flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, -+ struct nf_flow_route *route, -+ enum flow_offload_tuple_dir dir) -+{ -+ struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; -+ struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; -+ struct dst_entry *dst = route->tuple[dir].dst; -+ -+ ft->dir = dir; -+ -+ switch (ctt->src.l3num) { -+ case NFPROTO_IPV4: -+ ft->src_v4 = ctt->src.u3.in; -+ ft->dst_v4 = ctt->dst.u3.in; -+ ft->mtu = ip_dst_mtu_maybe_forward(dst, true); -+ break; -+ case NFPROTO_IPV6: -+ ft->src_v6 = ctt->src.u3.in6; -+ ft->dst_v6 = ctt->dst.u3.in6; -+ ft->mtu = ip6_dst_mtu_forward(dst); -+ break; -+ } -+ -+ ft->l3proto = ctt->src.l3num; -+ ft->l4proto = ctt->dst.protonum; -+ ft->src_port = ctt->src.u.tcp.port; -+ ft->dst_port = ctt->dst.u.tcp.port; -+ -+ ft->iifidx = route->tuple[dir].ifindex; -+ ft->oifidx = route->tuple[!dir].ifindex; -+ ft->dst_cache = dst; -+} -+ -+struct flow_offload * -+flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route) -+{ -+ struct flow_offload_entry *entry; -+ struct flow_offload *flow; -+ -+ if (unlikely(nf_ct_is_dying(ct) || -+ !atomic_inc_not_zero(&ct->ct_general.use))) -+ return NULL; -+ -+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC); -+ if (!entry) -+ goto err_ct_refcnt; -+ -+ flow = &entry->flow; -+ -+ if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst)) -+ goto err_dst_cache_original; -+ -+ if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst)) -+ goto err_dst_cache_reply; -+ -+ entry->ct = ct; -+ -+ flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_ORIGINAL); -+ flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_REPLY); -+ -+ if (ct->status & IPS_SRC_NAT) -+ flow->flags |= FLOW_OFFLOAD_SNAT; -+ else if (ct->status & IPS_DST_NAT) -+ flow->flags |= FLOW_OFFLOAD_DNAT; -+ -+ return flow; -+ -+err_dst_cache_reply: -+ dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst); -+err_dst_cache_original: -+ kfree(entry); -+err_ct_refcnt: -+ nf_ct_put(ct); -+ -+ return NULL; -+} -+EXPORT_SYMBOL_GPL(flow_offload_alloc); -+ -+void flow_offload_free(struct flow_offload *flow) -+{ -+ struct flow_offload_entry *e; -+ -+ dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache); -+ dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache); -+ e = container_of(flow, struct flow_offload_entry, flow); -+ nf_ct_delete(e->ct, 0, 0); -+ nf_ct_put(e->ct); -+ kfree_rcu(e, rcu_head); -+} -+EXPORT_SYMBOL_GPL(flow_offload_free); -+ -+void flow_offload_dead(struct flow_offload *flow) -+{ -+ flow->flags |= FLOW_OFFLOAD_DYING; -+} -+EXPORT_SYMBOL_GPL(flow_offload_dead); -+ -+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); -+ rhashtable_insert_fast(&flow_table->rhashtable, -+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, -+ *flow_table->type->params); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(flow_offload_add); -+ -+static void flow_offload_del(struct nf_flowtable *flow_table, -+ struct flow_offload *flow) -+{ -+ rhashtable_remove_fast(&flow_table->rhashtable, -+ &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, -+ *flow_table->type->params); -+ rhashtable_remove_fast(&flow_table->rhashtable, -+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, -+ *flow_table->type->params); -+ -+ flow_offload_free(flow); -+} -+ -+struct flow_offload_tuple_rhash * -+flow_offload_lookup(struct nf_flowtable *flow_table, -+ struct flow_offload_tuple *tuple) -+{ -+ return rhashtable_lookup_fast(&flow_table->rhashtable, tuple, -+ *flow_table->type->params); -+} -+EXPORT_SYMBOL_GPL(flow_offload_lookup); -+ -+int nf_flow_table_iterate(struct nf_flowtable *flow_table, -+ void (*iter)(struct flow_offload *flow, void *data), -+ void *data) -+{ -+ struct flow_offload_tuple_rhash *tuplehash; -+ struct rhashtable_iter hti; -+ struct flow_offload *flow; -+ int err; -+ -+ err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); -+ if (err) -+ return err; -+ -+ rhashtable_walk_start(&hti); -+ -+ while ((tuplehash = rhashtable_walk_next(&hti))) { -+ if (IS_ERR(tuplehash)) { -+ err = PTR_ERR(tuplehash); -+ if (err != -EAGAIN) -+ goto out; -+ -+ continue; -+ } -+ if (tuplehash->tuple.dir) -+ continue; -+ -+ flow = container_of(tuplehash, struct flow_offload, tuplehash[0]); -+ -+ iter(flow, data); -+ } -+out: -+ rhashtable_walk_stop(&hti); -+ rhashtable_walk_exit(&hti); -+ -+ return err; -+} -+EXPORT_SYMBOL_GPL(nf_flow_table_iterate); -+ -+static inline bool nf_flow_has_expired(const struct flow_offload *flow) -+{ -+ return (__s32)(flow->timeout - (u32)jiffies) <= 0; -+} -+ -+static inline bool nf_flow_is_dying(const struct flow_offload *flow) -+{ -+ return flow->flags & FLOW_OFFLOAD_DYING; -+} -+ -+static int nf_flow_offload_gc_step(struct nf_flowtable *flow_table) -+{ -+ struct flow_offload_tuple_rhash *tuplehash; -+ struct rhashtable_iter hti; -+ struct flow_offload *flow; -+ int err; -+ -+ err = rhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL); -+ if (err) -+ return 0; -+ -+ rhashtable_walk_start(&hti); -+ -+ while ((tuplehash = rhashtable_walk_next(&hti))) { -+ if (IS_ERR(tuplehash)) { -+ err = PTR_ERR(tuplehash); -+ if (err != -EAGAIN) -+ goto out; -+ -+ continue; -+ } -+ if (tuplehash->tuple.dir) -+ continue; -+ -+ flow = container_of(tuplehash, struct flow_offload, tuplehash[0]); -+ -+ if (nf_flow_has_expired(flow) || -+ nf_flow_is_dying(flow)) -+ flow_offload_del(flow_table, flow); -+ } -+out: -+ rhashtable_walk_stop(&hti); -+ rhashtable_walk_exit(&hti); -+ -+ return 1; -+} -+ -+void nf_flow_offload_work_gc(struct work_struct *work) -+{ -+ struct nf_flowtable *flow_table; -+ -+ flow_table = container_of(work, struct nf_flowtable, gc_work.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) -+{ -+ struct tcphdr *tcph; -+ -+ if (!pskb_may_pull(skb, thoff + sizeof(*tcph)) || -+ skb_try_make_writable(skb, thoff + sizeof(*tcph))) -+ return -1; -+ -+ tcph = (void *)(skb_network_header(skb) + thoff); -+ inet_proto_csum_replace2(&tcph->check, skb, port, new_port, true); -+ -+ return 0; -+} -+ -+static int nf_flow_nat_port_udp(struct sk_buff *skb, unsigned int thoff, -+ __be16 port, __be16 new_port) -+{ -+ struct udphdr *udph; -+ -+ if (!pskb_may_pull(skb, thoff + sizeof(*udph)) || -+ skb_try_make_writable(skb, thoff + sizeof(*udph))) -+ return -1; -+ -+ udph = (void *)(skb_network_header(skb) + thoff); -+ if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { -+ inet_proto_csum_replace2(&udph->check, skb, port, -+ new_port, true); -+ if (!udph->check) -+ udph->check = CSUM_MANGLED_0; -+ } -+ -+ return 0; -+} -+ -+static int nf_flow_nat_port(struct sk_buff *skb, unsigned int thoff, -+ u8 protocol, __be16 port, __be16 new_port) -+{ -+ switch (protocol) { -+ case IPPROTO_TCP: -+ if (nf_flow_nat_port_tcp(skb, thoff, port, new_port) < 0) -+ return NF_DROP; -+ break; -+ case IPPROTO_UDP: -+ if (nf_flow_nat_port_udp(skb, thoff, port, new_port) < 0) -+ return NF_DROP; -+ break; -+ } -+ -+ return 0; -+} -+ -+int nf_flow_snat_port(const struct flow_offload *flow, -+ struct sk_buff *skb, unsigned int thoff, -+ u8 protocol, enum flow_offload_tuple_dir dir) -+{ -+ struct flow_ports *hdr; -+ __be16 port, new_port; -+ -+ if (!pskb_may_pull(skb, thoff + sizeof(*hdr)) || -+ skb_try_make_writable(skb, thoff + sizeof(*hdr))) -+ return -1; -+ -+ hdr = (void *)(skb_network_header(skb) + thoff); -+ -+ switch (dir) { -+ case FLOW_OFFLOAD_DIR_ORIGINAL: -+ port = hdr->source; -+ new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port; -+ hdr->source = new_port; -+ break; -+ case FLOW_OFFLOAD_DIR_REPLY: -+ port = hdr->dest; -+ new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port; -+ hdr->dest = new_port; -+ break; -+ default: -+ return -1; -+ } -+ -+ return nf_flow_nat_port(skb, thoff, protocol, port, new_port); -+} -+EXPORT_SYMBOL_GPL(nf_flow_snat_port); -+ -+int nf_flow_dnat_port(const struct flow_offload *flow, -+ struct sk_buff *skb, unsigned int thoff, -+ u8 protocol, enum flow_offload_tuple_dir dir) -+{ -+ struct flow_ports *hdr; -+ __be16 port, new_port; -+ -+ if (!pskb_may_pull(skb, thoff + sizeof(*hdr)) || -+ skb_try_make_writable(skb, thoff + sizeof(*hdr))) -+ return -1; -+ -+ hdr = (void *)(skb_network_header(skb) + thoff); -+ -+ switch (dir) { -+ case FLOW_OFFLOAD_DIR_ORIGINAL: -+ port = hdr->dest; -+ new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_port; -+ hdr->dest = new_port; -+ break; -+ case FLOW_OFFLOAD_DIR_REPLY: -+ port = hdr->source; -+ new_port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_port; -+ hdr->source = new_port; -+ break; -+ default: -+ return -1; -+ } -+ -+ return nf_flow_nat_port(skb, thoff, protocol, port, new_port); -+} -+EXPORT_SYMBOL_GPL(nf_flow_dnat_port); -+ -+static void nf_flow_table_do_cleanup(struct flow_offload *flow, void *data) -+{ -+ struct net_device *dev = data; -+ -+ if (dev && flow->tuplehash[0].tuple.iifidx != dev->ifindex) -+ return; -+ -+ flow_offload_dead(flow); -+} -+ -+static void nf_flow_table_iterate_cleanup(struct nf_flowtable *flowtable, -+ void *data) -+{ -+ nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, data); -+ flush_delayed_work(&flowtable->gc_work); -+} -+ -+void nf_flow_table_cleanup(struct net *net, struct net_device *dev) -+{ -+ nft_flow_table_iterate(net, nf_flow_table_iterate_cleanup, dev); -+} -+EXPORT_SYMBOL_GPL(nf_flow_table_cleanup); -+ -+void nf_flow_table_free(struct nf_flowtable *flow_table) -+{ -+ nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); -+ WARN_ON(!nf_flow_offload_gc_step(flow_table)); -+} -+EXPORT_SYMBOL_GPL(nf_flow_table_free); -+ -+static int nf_flow_table_netdev_event(struct notifier_block *this, -+ unsigned long event, void *ptr) -+{ -+ struct net_device *dev = netdev_notifier_info_to_dev(ptr); -+ -+ if (event != NETDEV_DOWN) -+ return NOTIFY_DONE; -+ -+ nf_flow_table_cleanup(dev_net(dev), dev); -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block flow_offload_netdev_notifier = { -+ .notifier_call = nf_flow_table_netdev_event, -+}; -+ -+static int __init nf_flow_table_module_init(void) -+{ -+ return register_netdevice_notifier(&flow_offload_netdev_notifier); -+} -+ -+static void __exit nf_flow_table_module_exit(void) -+{ -+ unregister_netdevice_notifier(&flow_offload_netdev_notifier); -+} -+ -+module_init(nf_flow_table_module_init); -+module_exit(nf_flow_table_module_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); |