kernel: fix conntrack leak for flow_offload connections and timeout

This commit is contained in:
coolsnowwolf 2018-06-14 22:13:13 +08:00
parent bce04f5924
commit 6eab209732
17 changed files with 229 additions and 571 deletions

View File

@ -1,7 +1,7 @@
#src-git packages https://git.openwrt.org/feed/packages.git^1b73f267eae2dedc18969b70ed7c5d9b02288bac
src-git packages https://github.com/openwrt/packages.git
#src-git luci https://git.openwrt.org/project/luci.git^7d55be315d758b2a40494e732d7bdc300ee15c00
src-git luci https://github.com/openwrt/luci.git^80cb4fef8c7db0dadc373fef122d7abb092a7191
src-git luci https://github.com/openwrt/luci.git
#src-git luci https://github.com/openwrt/luci.git^80cb4fef8c7db0dadc373fef122d7abb092a7191
#src-git luci https://github.com/openwrt/luci.git;openwrt-18.06
src-git routing https://git.openwrt.org/feed/routing.git;openwrt-18.06
src-git telephony https://github.com/openwrt/telephony.git;openwrt-18.06

View File

@ -21,7 +21,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
static struct pernet_operations clusterip_net_ops = {
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6477,6 +6477,12 @@ static int __net_init nf_tables_init_net(struct net *net)
@@ -6477,6 +6477,12 @@ static int __net_init nf_tables_init_net
return 0;
}
@ -34,7 +34,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
int __nft_release_basechain(struct nft_ctx *ctx)
{
struct nft_rule *rule, *nr;
@@ -6554,6 +6560,7 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
@@ -6554,6 +6560,7 @@ static void __nft_release_afinfo(struct
static struct pernet_operations nf_tables_net_ops = {
.init = nf_tables_init_net,
@ -44,7 +44,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
static int __init nf_tables_module_init(void)
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1093,10 +1093,15 @@ static int __net_init nfnl_log_net_init(struct net *net)
@@ -1093,10 +1093,15 @@ static int __net_init nfnl_log_net_init(
static void __net_exit nfnl_log_net_exit(struct net *net)
{
@ -62,7 +62,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
static struct pernet_operations nfnl_log_net_ops = {
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1512,10 +1512,15 @@ static int __net_init nfnl_queue_net_init(struct net *net)
@@ -1512,10 +1512,15 @@ static int __net_init nfnl_queue_net_ini
static void __net_exit nfnl_queue_net_exit(struct net *net)
{
@ -80,7 +80,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1785,8 +1785,17 @@ static int __net_init xt_net_init(struct net *net)
@@ -1785,8 +1785,17 @@ static int __net_init xt_net_init(struct
return 0;
}

View File

@ -0,0 +1,110 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 13 Jun 2018 12:33:39 +0200
Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout
corner case
The full teardown of offloaded flows is deferred to a gc work item,
however processing of packets by netfilter needs to happen immediately
after a teardown is requested, because the conntrack state needs to be
fixed up.
Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete,
the netfilter conntrack gc can accidentally bump the timeout of a
connection where offload was just stopped, causing a conntrack entry
leak.
Fix this by moving the conntrack timeout bumping from conntrack core to
the nf_flow_offload and add a check to prevent bogus timeout bumps.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -978,18 +978,6 @@ static bool gc_worker_can_early_drop(con
return false;
}
-#define DAY (86400 * HZ)
-
-/* Set an arbitrary timeout large enough not to ever expire, this save
- * us a check for the IPS_OFFLOAD_BIT from the packet path via
- * nf_ct_is_expired().
- */
-static void nf_ct_offload_timeout(struct nf_conn *ct)
-{
- if (nf_ct_expires(ct) < DAY / 2)
- ct->timeout = nfct_time_stamp + DAY;
-}
-
static void gc_worker(struct work_struct *work)
{
unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
@@ -1026,10 +1014,8 @@ static void gc_worker(struct work_struct
tmp = nf_ct_tuplehash_to_ctrack(h);
scanned++;
- if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
- nf_ct_offload_timeout(tmp);
+ if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
continue;
- }
if (nf_ct_is_expired(tmp)) {
nf_ct_gc_expired(tmp);
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -185,8 +185,27 @@ static const struct rhashtable_params nf
.automatic_shrinking = true,
};
+#define DAY (86400 * HZ)
+
+/* Set an arbitrary timeout large enough not to ever expire, this save
+ * us a check for the IPS_OFFLOAD_BIT from the packet path via
+ * nf_ct_is_expired().
+ */
+static void nf_ct_offload_timeout(struct flow_offload *flow)
+{
+ struct flow_offload_entry *entry;
+ struct nf_conn *ct;
+
+ entry = container_of(flow, struct flow_offload_entry, flow);
+ ct = entry->ct;
+
+ if (nf_ct_expires(ct) < DAY / 2)
+ ct->timeout = nfct_time_stamp + DAY;
+}
+
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
{
+ nf_ct_offload_timeout(flow);
flow->timeout = (u32)jiffies;
rhashtable_insert_fast(&flow_table->rhashtable,
@@ -307,6 +326,8 @@ static int nf_flow_offload_gc_step(struc
rhashtable_walk_start(&hti);
while ((tuplehash = rhashtable_walk_next(&hti))) {
+ bool teardown;
+
if (IS_ERR(tuplehash)) {
err = PTR_ERR(tuplehash);
if (err != -EAGAIN)
@@ -319,9 +340,13 @@ static int nf_flow_offload_gc_step(struc
flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
- if (nf_flow_has_expired(flow) ||
- (flow->flags & (FLOW_OFFLOAD_DYING |
- FLOW_OFFLOAD_TEARDOWN)))
+ teardown = flow->flags & (FLOW_OFFLOAD_DYING |
+ FLOW_OFFLOAD_TEARDOWN);
+
+ if (!teardown)
+ nf_ct_offload_timeout(flow);
+
+ if (nf_flow_has_expired(flow) || teardown)
flow_offload_del(flow_table, flow);
}
out:

View File

@ -0,0 +1,24 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Jun 2018 11:20:09 +0200
Subject: [PATCH] netfilter: nf_flow_table: fix up ct state of flows after
timeout
If a connection simply times out instead of being torn down, it is left
active with a long timeout. Fix this by calling flow_offload_fixup_ct_state
here as well.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -233,6 +233,9 @@ static void flow_offload_del(struct nf_f
e = container_of(flow, struct flow_offload_entry, flow);
clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
+ if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
+ flow_offload_fixup_ct_state(e->ct);
+
flow_offload_free(flow);
}

View File

@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
--- /dev/null
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -0,0 +1,365 @@
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
+ *
@ -326,6 +326,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ if (!this_dst || !other_dst)
+ return -ENOENT;
+
+ if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
+ return -EINVAL;
+
+ route->tuple[dir].dst = this_dst;
+ route->tuple[dir].ifindex = xt_in(par)->ifindex;
+ route->tuple[!dir].dst = other_dst;

View File

@ -1,80 +0,0 @@
--- a/drivers/net/phy/mdio-boardinfo.c
+++ b/drivers/net/phy/mdio-boardinfo.c
@@ -15,8 +15,10 @@
#include "mdio-boardinfo.h"
-static LIST_HEAD(mdio_board_list);
-static DEFINE_MUTEX(mdio_board_lock);
+LIST_HEAD(mdio_board_list);
+EXPORT_SYMBOL_GPL(mdio_board_list);
+DEFINE_MUTEX(mdio_board_lock);
+EXPORT_SYMBOL_GPL(mdio_board_lock);
/**
* mdiobus_setup_mdiodev_from_board_info - create and setup MDIO devices
--- a/drivers/net/phy/mdio-boardinfo.h
+++ b/drivers/net/phy/mdio-boardinfo.h
@@ -15,6 +15,12 @@ struct mdio_board_entry {
struct mdio_board_info board_info;
};
+/* mdio_board_lock protects mdio_board_list
+ * only mdio_bus components are allowed to use these symbols.
+ */
+extern struct mutex mdio_board_lock;
+extern struct list_head mdio_board_list;
+
void mdiobus_setup_mdiodev_from_board_info(struct mii_bus *bus,
int (*cb)
(struct mii_bus *bus,
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -88,6 +88,8 @@ bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
}
EXPORT_SYMBOL(mdiobus_is_registered_device);
+#include "mdio-boardinfo.h"
+
/**
* mdiobus_alloc_size - allocate a mii_bus structure
* @size: extra amount of memory to allocate for private storage.
@@ -455,6 +457,17 @@ void mdiobus_free(struct mii_bus *bus)
}
EXPORT_SYMBOL(mdiobus_free);
+static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus,
+ struct phy_device *phydev,
+ struct mdio_board_info *bi)
+{
+ if (strcmp(bus->id, bi->bus_id) ||
+ bi->mdio_addr != phydev->mdio.addr)
+ return;
+
+ phydev->mdio.dev.platform_data = (void *) bi->platform_data;
+}
+
/**
* mdiobus_scan - scan a bus for MDIO devices.
* @bus: mii_bus to scan
@@ -470,6 +483,7 @@ EXPORT_SYMBOL(mdiobus_free);
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
+ struct mdio_board_entry *be;
int err;
phydev = get_phy_device(bus, addr, false);
@@ -482,6 +496,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
*/
of_mdiobus_link_mdiodev(bus, &phydev->mdio);
+ mutex_lock(&mdio_board_lock);
+ list_for_each_entry(be, &mdio_board_list, list)
+ mdiobus_setup_phydev_from_boardinfo(bus, phydev,
+ &be->board_info);
+ mutex_unlock(&mdio_board_lock);
+
err = phy_device_register(phydev);
if (err) {
phy_device_free(phydev);

View File

@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
*/
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2492,6 +2492,10 @@ static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
@@ -2491,6 +2491,10 @@ static inline int pskb_trim(struct sk_bu
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
* @skb: buffer to alter
@@ -2622,16 +2626,6 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length)
@@ -2621,16 +2625,6 @@ static inline struct sk_buff *dev_alloc_
}
@ -101,9 +101,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
help
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2988,10 +2988,20 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
dev_queue_xmit_nit(skb, dev);
}
@@ -2982,10 +2982,20 @@ static int xmit_one(struct sk_buff *skb,
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
dev_queue_xmit_nit(skb, dev);
- len = skb->len;
- trace_net_dev_start_xmit(skb, dev);
@ -136,7 +136,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include <net/protocol.h>
#include <net/dst.h>
@@ -499,6 +500,22 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
@@ -499,6 +500,22 @@ skb_fail:
}
EXPORT_SYMBOL(__napi_alloc_skb);
@ -161,7 +161,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
{
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -172,6 +172,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
@@ -172,6 +172,12 @@ __be16 eth_type_trans(struct sk_buff *sk
const struct ethhdr *eth;
skb->dev = dev;

View File

@ -14,7 +14,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
@@ -268,6 +268,7 @@ static int bgmac_probe(struct bcma_device *core)
@@ -268,6 +268,7 @@ static int bgmac_probe(struct bcma_devic
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;

View File

@ -29,7 +29,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2805,6 +2805,8 @@ static const struct file_operations proc_locks_operations = {
@@ -2805,6 +2805,8 @@ static const struct file_operations proc
static int __init proc_locks_init(void)
{
@ -51,7 +51,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ bool "Strip non-essential /proc functionality to reduce code size"
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -106,6 +106,9 @@ static const struct file_operations proc_consoles_operations = {
@@ -106,6 +106,9 @@ static const struct file_operations proc
static int __init proc_consoles_init(void)
{
@ -63,7 +63,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -145,7 +145,10 @@ static const struct file_operations proc_tty_drivers_operations = {
@@ -145,7 +145,10 @@ static const struct file_operations proc
void proc_tty_register_driver(struct tty_driver *driver)
{
struct proc_dir_entry *ent;
@ -75,7 +75,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!driver->driver_name || driver->proc_entry ||
!driver->ops->proc_fops)
return;
@@ -162,6 +165,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver)
@@ -162,6 +165,9 @@ void proc_tty_unregister_driver(struct t
{
struct proc_dir_entry *ent;
@ -85,7 +85,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
ent = driver->proc_entry;
if (!ent)
return;
@@ -176,6 +182,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver)
@@ -176,6 +182,9 @@ void proc_tty_unregister_driver(struct t
*/
void __init proc_tty_init(void)
{
@ -166,7 +166,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(cons
struct proc_dir_entry *pde;
struct ipc_proc_iface *iface;
@ -178,7 +178,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return;
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -42,6 +42,8 @@ static const struct file_operations execdomains_proc_fops = {
@@ -42,6 +42,8 @@ static const struct file_operations exec
static int __init proc_execdomains_init(void)
{
@ -189,7 +189,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -396,6 +396,9 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
@@ -396,6 +396,9 @@ void register_irq_proc(unsigned int irq,
void __maybe_unused *irqp = (void *)(unsigned long) irq;
char name [MAX_NAMELEN];
@ -199,7 +199,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
return;
@@ -449,6 +452,9 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
@@ -449,6 +452,9 @@ void unregister_irq_proc(unsigned int ir
{
char name [MAX_NAMELEN];
@ -221,7 +221,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!root_irq_dir)
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -389,6 +389,8 @@ static int __init init_timer_list_procfs(void)
@@ -389,6 +389,8 @@ static int __init init_timer_list_procfs
{
struct proc_dir_entry *pe;
@ -232,7 +232,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return -ENOMEM;
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2769,6 +2769,8 @@ static const struct file_operations proc_vmalloc_operations = {
@@ -2769,6 +2769,8 @@ static const struct file_operations proc
static int __init proc_vmalloc_init(void)
{
@ -271,7 +271,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (vn->proc_vlan_conf)
remove_proc_entry(name_conf, vn->proc_vlan_dir);
@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net *net)
@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net
{
struct vlan_net *vn = net_generic(net, vlan_net_id);
@ -283,7 +283,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
goto err;
--- a/net/core/net-procfs.c
+++ b/net/core/net-procfs.c
@@ -320,10 +320,12 @@ static int __net_init dev_proc_net_init(struct net *net)
@@ -320,10 +320,12 @@ static int __net_init dev_proc_net_init(
if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
goto out;
@ -298,7 +298,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
goto out_softnet;
if (wext_proc_init(net))
@@ -332,9 +334,11 @@ static int __net_init dev_proc_net_init(struct net *net)
@@ -332,9 +334,11 @@ static int __net_init dev_proc_net_init(
out:
return rc;
out_ptype:
@ -312,7 +312,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
out_dev:
remove_proc_entry("dev", net->proc_net);
goto out;
@@ -344,8 +348,10 @@ static void __net_exit dev_proc_net_exit(struct net *net)
@@ -344,8 +348,10 @@ static void __net_exit dev_proc_net_exit
{
wext_proc_exit(net);
@ -327,7 +327,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -3378,6 +3378,8 @@ static __net_initdata struct pernet_operations proto_net_ops = {
@@ -3378,6 +3378,8 @@ static __net_initdata struct pernet_oper
static int __init proto_init(void)
{
@ -338,7 +338,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2731,10 +2731,12 @@ static const struct file_operations fib_route_fops = {
@@ -2731,10 +2731,12 @@ static const struct file_operations fib_
int __net_init fib_proc_init(struct net *net)
{
@ -353,7 +353,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
&fib_triestat_fops))
goto out2;
@@ -2744,17 +2746,21 @@ int __net_init fib_proc_init(struct net *net)
@@ -2744,17 +2746,21 @@ int __net_init fib_proc_init(struct net
return 0;
out3:
@ -381,7 +381,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -557,6 +557,9 @@ static __net_initdata struct pernet_operations ip_proc_ops = {
@@ -557,6 +557,9 @@ static __net_initdata struct pernet_oper
int __init ip_misc_proc_init(void)
{
@ -393,7 +393,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -427,6 +427,9 @@ static struct pernet_operations ip_rt_proc_ops __net_initdata = {
@@ -427,6 +427,9 @@ static struct pernet_operations ip_rt_pr
static int __init ip_rt_proc_init(void)
{

View File

@ -156,7 +156,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -199,10 +199,16 @@ int flow_offload_add(struct nf_flowtable
@@ -218,10 +218,16 @@ int flow_offload_add(struct nf_flowtable
}
EXPORT_SYMBOL_GPL(flow_offload_add);
@ -173,9 +173,9 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
rhashtable_remove_fast(&flow_table->rhashtable,
&flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
@@ -214,6 +220,9 @@ static void flow_offload_del(struct nf_f
e = container_of(flow, struct flow_offload_entry, flow);
clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
@@ -236,6 +242,9 @@ static void flow_offload_del(struct nf_f
if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
flow_offload_fixup_ct_state(e->ct);
+ if (nf_flow_in_hw(flow))
+ nf_flow_offload_hw_del(net, flow);
@ -183,32 +183,17 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
flow_offload_free(flow);
}
@@ -307,6 +316,7 @@ static int nf_flow_offload_gc_step(struc
rhashtable_walk_start(&hti);
@@ -349,6 +358,9 @@ static int nf_flow_offload_gc_step(struc
if (!teardown)
nf_ct_offload_timeout(flow);
while ((tuplehash = rhashtable_walk_next(&hti))) {
+ bool teardown;
if (IS_ERR(tuplehash)) {
err = PTR_ERR(tuplehash);
if (err != -EAGAIN)
@@ -319,9 +329,13 @@ static int nf_flow_offload_gc_step(struc
flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
- if (nf_flow_has_expired(flow) ||
- (flow->flags & (FLOW_OFFLOAD_DYING |
- FLOW_OFFLOAD_TEARDOWN)))
+ teardown = flow->flags & (FLOW_OFFLOAD_DYING |
+ FLOW_OFFLOAD_TEARDOWN);
+
+ if (nf_flow_in_hw(flow) && !teardown)
+ continue;
+
+ if (nf_flow_has_expired(flow) || teardown)
if (nf_flow_has_expired(flow) || teardown)
flow_offload_del(flow_table, flow);
}
out:
@@ -456,10 +470,43 @@ int nf_flow_dnat_port(const struct flow_
@@ -484,10 +496,43 @@ int nf_flow_dnat_port(const struct flow_
}
EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
@ -252,7 +237,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
err = rhashtable_init(&flowtable->rhashtable,
@@ -497,6 +544,8 @@ static void nf_flow_table_iterate_cleanu
@@ -525,6 +570,8 @@ static void nf_flow_table_iterate_cleanu
{
nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
flush_delayed_work(&flowtable->gc_work);
@ -261,7 +246,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
}
void nf_flow_table_cleanup(struct net *net, struct net_device *dev)
@@ -510,6 +559,26 @@ void nf_flow_table_cleanup(struct net *n
@@ -538,6 +585,26 @@ void nf_flow_table_cleanup(struct net *n
}
EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
@ -288,7 +273,7 @@ Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
void nf_flow_table_free(struct nf_flowtable *flow_table)
{
mutex_lock(&flowtable_lock);
@@ -519,9 +588,58 @@ void nf_flow_table_free(struct nf_flowta
@@ -547,9 +614,58 @@ void nf_flow_table_free(struct nf_flowta
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);

View File

@ -26,9 +26,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -332,7 +332,7 @@ static int nf_flow_offload_gc_step(struc
teardown = flow->flags & (FLOW_OFFLOAD_DYING |
FLOW_OFFLOAD_TEARDOWN);
@@ -358,7 +358,7 @@ static int nf_flow_offload_gc_step(struc
if (!teardown)
nf_ct_offload_timeout(flow);
- if (nf_flow_in_hw(flow) && !teardown)
+ if ((flow->flags & FLOW_OFFLOAD_KEEP) && !teardown)

View File

@ -0,0 +1,25 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 27 Apr 2018 14:42:14 +0200
Subject: [PATCH] netfilter: nf_flow_table: rework private driver data
Move the timeout out of the union, since it can be shared between the
driver and the stack. Add a private pointer that the driver can use to
point to its own data structures
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -81,9 +81,10 @@ struct flow_offload_tuple_rhash {
struct flow_offload {
struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
u32 flags;
+ u32 timeout;
union {
/* Your private driver data here. */
- u32 timeout;
+ void *priv;
};
};

View File

@ -90,7 +90,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
}
@@ -141,20 +143,29 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
@@ -141,20 +143,29 @@ static struct net_device_stats *ip6_get_
static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
{
@ -125,7 +125,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_any(&t->parms.raddr) &&
@@ -162,7 +173,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
@@ -162,7 +173,7 @@ ip6_tnl_lookup(struct net *net, const st
return t;
}
@ -134,7 +134,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(remote, &t->parms.raddr) &&
ipv6_addr_any(&t->parms.laddr) &&
@@ -202,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
@@ -202,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
prio = 1;
@ -143,7 +143,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
}
return &ip6n->tnls[prio][h];
}
@@ -383,6 +394,12 @@ ip6_tnl_dev_uninit(struct net_device *dev)
@@ -383,6 +394,12 @@ ip6_tnl_dev_uninit(struct net_device *de
struct net *net = t->net;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
@ -264,7 +264,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
const struct tnl_ptk_info *tpi,
struct metadata_dst *tun_dst,
@@ -831,6 +949,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
@@ -831,6 +949,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl
skb_reset_network_header(skb);
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
@ -292,7 +292,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
@@ -962,6 +1101,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
@@ -962,6 +1101,7 @@ static void init_tel_txopt(struct ipv6_t
opt->ops.opt_nflen = 8;
}
@ -300,7 +300,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
/**
* ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
* @t: the outgoing tunnel device
@@ -1303,6 +1443,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -1303,6 +1443,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
{
struct ip6_tnl *t = netdev_priv(dev);
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
@ -308,7 +308,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
int encap_limit = -1;
__u16 offset;
struct flowi6 fl6;
@@ -1365,6 +1506,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -1365,6 +1506,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
@ -327,7 +327,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
@@ -1493,6 +1646,14 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
@@ -1493,6 +1646,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
t->parms.link = p->link;
t->parms.proto = p->proto;
t->parms.fwmark = p->fwmark;
@ -342,7 +342,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
dst_cache_reset(&t->dst_cache);
ip6_tnl_link_config(t);
return 0;
@@ -1531,6 +1692,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
@@ -1531,6 +1692,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
p->flowinfo = u->flowinfo;
p->link = u->link;
p->proto = u->proto;
@ -350,7 +350,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
memcpy(p->name, u->name, sizeof(u->name));
}
@@ -1912,6 +2074,15 @@ static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -1912,6 +2074,15 @@ static int ip6_tnl_validate(struct nlatt
return 0;
}
@ -366,7 +366,7 @@ Signed-off-by: Steven Barth <cyrus@openwrt.org>
static void ip6_tnl_netlink_parms(struct nlattr *data[],
struct __ip6_tnl_parm *parms)
{
@@ -1949,6 +2120,46 @@ static void ip6_tnl_netlink_parms(struct nlattr *data[],
@@ -1949,6 +2120,46 @@ static void ip6_tnl_netlink_parms(struct
if (data[IFLA_IPTUN_FWMARK])
parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);

View File

@ -9,11 +9,11 @@ Signed-off-by: John Crispin <john@phrozen.org>
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -382,6 +382,74 @@ void phy_ethtool_ksettings_get(struct phy_device *phydev,
@@ -382,6 +382,73 @@ void phy_ethtool_ksettings_get(struct ph
}
EXPORT_SYMBOL(phy_ethtool_ksettings_get);
+int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+static int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = phydev->supported;
+
@ -35,7 +35,6 @@ Signed-off-by: John Crispin <john@phrozen.org>
+
+ return 0;
+}
+EXPORT_SYMBOL(phy_ethtool_gset);
+
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
+{
@ -86,12 +85,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
* @phydev: the phy_device struct
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -901,10 +901,12 @@ void phy_start_machine(struct phy_device *phydev);
void phy_stop_machine(struct phy_device *phydev);
void phy_trigger_machine(struct phy_device *phydev, bool sync);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
void phy_ethtool_ksettings_get(struct phy_device *phydev,
@@ -905,6 +905,7 @@ void phy_ethtool_ksettings_get(struct ph
struct ethtool_link_ksettings *cmd);
int phy_ethtool_ksettings_set(struct phy_device *phydev,
const struct ethtool_link_ksettings *cmd);

View File

@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* __LINUX_USB_PCI_QUIRKS_H */
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -465,7 +465,14 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev,
@@ -465,7 +465,14 @@ extern int usb_hcd_pci_probe(struct pci_
extern void usb_hcd_pci_remove(struct pci_dev *dev);
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);

View File

@ -1,393 +0,0 @@
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -53,6 +53,7 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+extern void br_dev_update_stats(struct net_device *dev, struct rtnl_link_stats64 *nlstats);
typedef int br_should_route_hook_t(struct sk_buff *skb);
extern br_should_route_hook_t __rcu *br_should_route_hook;
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -767,6 +767,7 @@ struct sk_buff {
#endif
__u8 ipvs_property:1;
__u8 inner_protocol_type:1;
+ __u8 fast_forwarded:1;
__u8 remcsum_offload:1;
#ifdef CONFIG_NET_SWITCHDEV
__u8 offload_fwd_mark:1;
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -71,14 +71,8 @@ struct nf_ct_event {
int report;
};
-struct nf_ct_event_notifier {
- int (*fcn)(unsigned int events, struct nf_ct_event *item);
-};
-
-int nf_conntrack_register_notifier(struct net *net,
- struct nf_ct_event_notifier *nb);
-void nf_conntrack_unregister_notifier(struct net *net,
- struct nf_ct_event_notifier *nb);
+extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb);
+extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb);
void nf_ct_deliver_cached_events(struct nf_conn *ct);
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
@@ -87,12 +81,8 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
static inline void
nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
{
- struct net *net = nf_ct_net(ct);
struct nf_conntrack_ecache *e;
- if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
- return;
-
e = nf_ct_ecache_find(ct);
if (e == NULL)
return;
@@ -104,22 +94,12 @@ static inline int
nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
u32 portid, int report)
{
- const struct net *net = nf_ct_net(ct);
-
- if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
- return 0;
-
return nf_conntrack_eventmask_report(1 << event, ct, portid, report);
}
static inline int
nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
{
- const struct net *net = nf_ct_net(ct);
-
- if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
- return 0;
-
return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
}
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -114,7 +114,7 @@ struct netns_ct {
struct ct_pcpu __percpu *pcpu_lists;
struct ip_conntrack_stat __percpu *stat;
- struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
+ struct atomic_notifier_head nf_conntrack_chain;
struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
struct nf_ip_net nf_ct_proto;
#if defined(CONFIG_NF_CONNTRACK_LABELS)
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -654,3 +654,27 @@ void br_port_flags_change(struct net_bridge_port *p, unsigned long mask)
if (mask & BR_AUTO_MASK)
nbp_update_port_count(br);
}
+
+/* Update bridge statistics for bridge packets processed by offload engines */
+void br_dev_update_stats(struct net_device *dev, struct rtnl_link_stats64 *nlstats)
+{
+ struct net_bridge *br;
+ struct pcpu_sw_netstats *stats;
+
+ /*
+ * Is this a bridge?
+ */
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ return;
+
+ br = netdev_priv(dev);
+ stats = per_cpu_ptr(br->stats, 0);
+
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets += nlstats->rx_packets;
+ stats->rx_bytes += nlstats->rx_bytes;
+ stats->tx_packets += nlstats->tx_packets;
+ stats->tx_bytes += nlstats->tx_bytes;
+ u64_stats_update_end(&stats->syncp);
+}
+EXPORT_SYMBOL_GPL(br_dev_update_stats);
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2979,8 +2979,14 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
unsigned int len;
int rc;
- if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
- dev_queue_xmit_nit(skb, dev);
+ /*
+ * If this skb has been fast forwarded then we don't want it to
+ * go to any taps (by definition we're trying to bypass them).
+ */
+ if (!skb->fast_forwarded) {
+ if (!list_empty(&ptype_all))
+ dev_queue_xmit_nit(skb, dev);
+ }
len = skb->len;
trace_net_dev_start_xmit(skb, dev);
@@ -4282,6 +4288,9 @@ void netdev_rx_handler_unregister(struct net_device *dev)
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+int (*fast_nat_recv)(struct sk_buff *skb) __rcu __read_mostly;
+EXPORT_SYMBOL_GPL(fast_nat_recv);
+
/*
* Limit the use of PFMEMALLOC reserves to those protocols that implement
* the special handling of PFMEMALLOC skbs.
@@ -4329,6 +4338,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type;
+ int (*fast_recv)(struct sk_buff *skb);
net_timestamp_check(!netdev_tstamp_prequeue, skb);
@@ -4355,6 +4365,12 @@ another_round:
goto out;
}
+ fast_recv = rcu_dereference(fast_nat_recv);
+ if (fast_recv && fast_recv(skb)) {
+ ret = NET_RX_SUCCESS;
+ goto out;
+ }
+
if (skb_skip_tc_classify(skb))
goto skip_classify;
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -2187,6 +2187,7 @@ int nf_conntrack_init_net(struct net *net)
ret = nf_conntrack_proto_pernet_init(net);
if (ret < 0)
goto err_proto;
+ ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain);
return 0;
err_proto:
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -18,6 +18,7 @@
#include <linux/stddef.h>
#include <linux/err.h>
#include <linux/percpu.h>
+#include <linux/notifier.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
@@ -120,19 +121,13 @@ static void ecache_work(struct work_struct *work)
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
u32 portid, int report)
{
- int ret = 0;
- struct net *net = nf_ct_net(ct);
- struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e;
- rcu_read_lock();
- notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
- if (!notify)
- goto out_unlock;
+ struct net *net = nf_ct_net(ct);
e = nf_ct_ecache_find(ct);
if (!e)
- goto out_unlock;
+ return 0;
if (nf_ct_is_confirmed(ct)) {
struct nf_ct_event item = {
@@ -144,32 +139,11 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
unsigned long missed = e->portid ? 0 : e->missed;
if (!((eventmask | missed) & e->ctmask))
- goto out_unlock;
-
- ret = notify->fcn(eventmask | missed, &item);
- if (unlikely(ret < 0 || missed)) {
- spin_lock_bh(&ct->lock);
- if (ret < 0) {
- /* This is a destroy event that has been
- * triggered by a process, we store the PORTID
- * to include it in the retransmission.
- */
- if (eventmask & (1 << IPCT_DESTROY)) {
- if (e->portid == 0 && portid != 0)
- e->portid = portid;
- e->state = NFCT_ECACHE_DESTROY_FAIL;
- } else {
- e->missed |= eventmask;
- }
- } else {
- e->missed &= ~missed;
- }
- spin_unlock_bh(&ct->lock);
- }
+ return 0;
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, eventmask | missed, &item);
}
-out_unlock:
- rcu_read_unlock();
- return ret;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
@@ -177,26 +151,19 @@ EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
* disabled softirqs */
void nf_ct_deliver_cached_events(struct nf_conn *ct)
{
- struct net *net = nf_ct_net(ct);
unsigned long events, missed;
- struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e;
struct nf_ct_event item;
- int ret;
-
- rcu_read_lock();
- notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
- if (notify == NULL)
- goto out_unlock;
+ struct net *net = nf_ct_net(ct);
e = nf_ct_ecache_find(ct);
if (e == NULL)
- goto out_unlock;
+ return;
events = xchg(&e->cache, 0);
if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct))
- goto out_unlock;
+ return;
/* We make a copy of the missed event cache without taking
* the lock, thus we may send missed events twice. However,
@@ -204,26 +171,22 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
missed = e->missed;
if (!((events | missed) & e->ctmask))
- goto out_unlock;
+ return;
item.ct = ct;
item.portid = 0;
item.report = 0;
- ret = notify->fcn(events | missed, &item);
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
+ events | missed,
+ &item);
- if (likely(ret == 0 && !missed))
- goto out_unlock;
+ if (likely(!missed))
+ return;
spin_lock_bh(&ct->lock);
- if (ret < 0)
- e->missed |= events;
- else
- e->missed &= ~missed;
+ e->missed &= ~missed;
spin_unlock_bh(&ct->lock);
-
-out_unlock:
- rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
@@ -257,40 +220,15 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
rcu_read_unlock();
}
-int nf_conntrack_register_notifier(struct net *net,
- struct nf_ct_event_notifier *new)
+int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb)
{
- int ret;
- struct nf_ct_event_notifier *notify;
-
- mutex_lock(&nf_ct_ecache_mutex);
- notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
- lockdep_is_held(&nf_ct_ecache_mutex));
- if (notify != NULL) {
- ret = -EBUSY;
- goto out_unlock;
- }
- rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
- ret = 0;
-
-out_unlock:
- mutex_unlock(&nf_ct_ecache_mutex);
- return ret;
+ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb);
}
EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
-void nf_conntrack_unregister_notifier(struct net *net,
- struct nf_ct_event_notifier *new)
+int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb)
{
- struct nf_ct_event_notifier *notify;
-
- mutex_lock(&nf_ct_ecache_mutex);
- notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb,
- lockdep_is_held(&nf_ct_ecache_mutex));
- BUG_ON(notify != new);
- RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL);
- mutex_unlock(&nf_ct_ecache_mutex);
- /* synchronize_rcu() is called from ctnetlink_exit. */
+ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb);
}
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -28,6 +28,7 @@
#include <linux/netlink.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
+#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/netfilter.h>
@@ -618,14 +619,15 @@ static size_t ctnetlink_nlmsg_size(const struct nf_conn *ct)
;
}
-static int
-ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
+static int ctnetlink_conntrack_event(struct notifier_block *this,
+ unsigned long events, void *ptr)
{
const struct nf_conntrack_zone *zone;
struct net *net;
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
struct nlattr *nest_parms;
+ struct nf_ct_event *item = ptr;
struct nf_conn *ct = item->ct;
struct sk_buff *skb;
unsigned int type;
@@ -3303,8 +3305,8 @@ static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
}
#ifdef CONFIG_NF_CONNTRACK_EVENTS
-static struct nf_ct_event_notifier ctnl_notifier = {
- .fcn = ctnetlink_conntrack_event,
+static struct notifier_block ctnl_notifier = {
+ .notifier_call = ctnetlink_conntrack_event,
};
static struct nf_exp_event_notifier ctnl_notifier_exp = {

View File

@ -1,10 +0,0 @@
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -35,6 +35,7 @@
/* Do not check the TCP window for incoming packets */
static int nf_ct_tcp_no_window_check __read_mostly = 1;
+EXPORT_SYMBOL_GPL(nf_ct_tcp_no_window_check);
/* "Be conservative in what you do,
be liberal in what you accept from others."