All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections
@ 2014-12-08 15:36 Florian Westphal
  2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Florian Westphal @ 2014-12-08 15:36 UTC (permalink / raw)
  To: netfilter-devel; +Cc: netdev, brouer

[ Pablo, in case you deem this too late for -next just let me know
and I will resend once its open again ]

This adds an optional forward routing cache extension for netfilter
connection tracking.

The memory cost is an additional 32 bytes per conntrack entry
on x86_64.

Unlike any other currently implemented connection tracking
extension the rtcache has no run-time tunables, it is always active.

Also, unlike other conntrack extensions, it can be built as a module,
in this case modprobe/rmmod are used to enable/disable the cache.

Forward test using netperf UDP_STREAM between two network namespaces
(connected via veth devices), tput:

With conntrack + reverse path filtering (rp_filter sysctl=1):
MIGRATED UDP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.12.2 () port 0 AF_INET
Socket  Message  Elapsed      Messages
 Size    Size     Time         Okay Errors   Throughput
 bytes   bytes    secs            #      #   10^6bits/sec

  212992      64   120.00    26333996      0     112.36
  212992           120.00    26279399            112.13

same, but with rtcache (this patch series):
  212992      64   120.00    34508693      0     147.24
  212992           120.00    34507838            147.23

same but with rp_filter=0 and no conntrack modules active:
  212992      64   120.00    42288748      0     180.43
  212992           120.00    42283439            180.41

IOW, this is only useful if conntrack is used anyway.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH nf-next 1/2] netfilter: conntrack: cache route for forwarded connections
  2014-12-08 15:36 [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Florian Westphal
@ 2014-12-08 15:36 ` Florian Westphal
  2014-12-08 22:33   ` Florian Westphal
  2016-04-28  8:05   ` [nf-next, " Charlemagne Lasse
  2014-12-08 15:36 ` [PATCH nf-next 2/2] netfilter: use conntrack rtcache if available Florian Westphal
  2014-12-10 14:13 ` [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Pablo Neira Ayuso
  2 siblings, 2 replies; 7+ messages in thread
From: Florian Westphal @ 2014-12-08 15:36 UTC (permalink / raw)
  To: netfilter-devel; +Cc: netdev, brouer, Florian Westphal

... to avoid per-packet FIB lookup if possible.

The cached dst is re-used provided the input interface
is the same as that of the previous packet in the same direction.

If not, the cached dst is invalidated.

For ipv6 we also need to store sernum, else dst_check doesn't work,
pointed out by Eric Dumazet.

This should speed up forwarding when conntrack is already in use
anyway, especially when using reverse path filtering -- active RPF
enforces two FIB lookups for each packet.

Before the routing cache removal this didn't matter since RPF was performed
only when route cache didn't yield a result; but without route cache it
comes at higher price.

Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
avoid holding on to dsts of 'frozen' conntracks.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 Changes since RFC:
  - add NETDEV_UNREGISTER, suggested by Julian
  - cache fib sernum to make ipv6 work, pointed out by Eric
  - make module unload work
  - remove ASSURED test, in case of -j DROP in prerouting or forward
    cache forward hook won't be reached anyway

 include/net/netfilter/nf_conntrack_extend.h  |   4 +
 include/net/netfilter/nf_conntrack_rtcache.h |  34 +++
 net/netfilter/Kconfig                        |  12 +
 net/netfilter/Makefile                       |   3 +
 net/netfilter/nf_conntrack_rtcache.c         | 387 +++++++++++++++++++++++++++
 5 files changed, 440 insertions(+)
 create mode 100644 include/net/netfilter/nf_conntrack_rtcache.h
 create mode 100644 net/netfilter/nf_conntrack_rtcache.c

diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 55d1504..1b00d57 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
 #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
 	NF_CT_EXT_SYNPROXY,
 #endif
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+	NF_CT_EXT_RTCACHE,
+#endif
 	NF_CT_EXT_NUM,
 };
 
@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
 #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
 #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
 #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
+#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
 
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct nf_ct_ext {
diff --git a/include/net/netfilter/nf_conntrack_rtcache.h b/include/net/netfilter/nf_conntrack_rtcache.h
new file mode 100644
index 0000000..e2fb302
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
@@ -0,0 +1,34 @@
+#include <linux/gfp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+struct dst_entry;
+
+struct nf_conn_dst_cache {
+	struct dst_entry *dst;
+	int iif;
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+	u32 cookie;
+#endif
+
+};
+
+struct nf_conn_rtcache {
+	struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
+};
+
+static inline
+struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+	return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
+#else
+	return NULL;
+#endif
+}
+
+static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
+					  enum ip_conntrack_dir dir)
+{
+	return rtc->cached_dst[dir].iif;
+}
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index b02660f..c213a61 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS
 
 	  If unsure, say `N'.
 
+config NF_CONNTRACK_RTCACHE
+	tristate "Cache route entries in conntrack objects"
+	depends on NETFILTER_ADVANCED
+	depends on NF_CONNTRACK
+	help
+	  If this option is enabled, the connection tracking code will
+	  cache routing information for each connection that is being
+	  forwarded, at a cost of 32 bytes per conntrack object.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+	  The module will be called nf_conntrack_rtcache.
+
 config NF_CONNTRACK_TIMEOUT
 	bool  'Connection tracking timeout'
 	depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 89f73a9..c174ab2 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 # connection tracking
 obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
 
+# optional conntrack route cache extension
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
+
 # SCTP protocol connection tracking
 obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
 obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
diff --git a/net/netfilter/nf_conntrack_rtcache.c b/net/netfilter/nf_conntrack_rtcache.c
new file mode 100644
index 0000000..65fef44
--- /dev/null
+++ b/net/netfilter/nf_conntrack_rtcache.c
@@ -0,0 +1,387 @@
+/* route cache for netfilter.
+ *
+ * (C) 2014 Red Hat GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/skbuff.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include <net/dst.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_rtcache.h>
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+#include <net/ip6_fib.h>
+#endif
+
+static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
+				      enum ip_conntrack_dir dir)
+{
+	struct dst_entry *dst = rtc->cached_dst[dir].dst;
+
+	dst_release(dst);
+}
+
+static void nf_conn_rtcache_destroy(struct nf_conn *ct)
+{
+	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+
+	if (!rtc)
+		return;
+
+	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
+	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
+}
+
+static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
+{
+	struct nf_conn_rtcache *rtc;
+
+	rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
+	if (rtc) {
+		rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
+		rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
+		rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
+		rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
+	}
+}
+
+static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
+{
+	if (nf_ct_is_untracked(ct))
+		return NULL;
+	return nf_ct_rtcache_find(ct);
+}
+
+static struct dst_entry *
+nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
+			enum ip_conntrack_dir dir)
+{
+	return rtc->cached_dst[dir].dst;
+}
+
+static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+	if (pf == NFPROTO_IPV6) {
+		const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+		if (rt->rt6i_node)
+			return (u32)rt->rt6i_node->fn_sernum;
+	}
+#endif
+	return 0;
+}
+
+static void nf_conn_rtcache_dst_set(int pf,
+				    struct nf_conn_rtcache *rtc,
+				    struct dst_entry *dst,
+				    enum ip_conntrack_dir dir, int iif)
+{
+	if (rtc->cached_dst[dir].iif != iif)
+		rtc->cached_dst[dir].iif = iif;
+
+	if (rtc->cached_dst[dir].dst != dst) {
+		struct dst_entry *old;
+
+		dst_hold(dst);
+
+		old = xchg(&rtc->cached_dst[dir].dst, dst);
+		dst_release(old);
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+		if (pf == NFPROTO_IPV6)
+			rtc->cached_dst[dir].cookie =
+				nf_rtcache_get_cookie(pf, dst);
+#endif
+	}
+}
+
+static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
+					 enum ip_conntrack_dir dir)
+{
+	struct dst_entry *old;
+
+	pr_debug("Invalidate iif %d for dir %d on cache %p\n",
+		 rtc->cached_dst[dir].iif, dir, rtc);
+
+	old = xchg(&rtc->cached_dst[dir].dst, NULL);
+	dst_release(old);
+	rtc->cached_dst[dir].iif = -1;
+}
+
+static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops,
+				  struct sk_buff *skb,
+				  const struct net_device *in,
+				  const struct net_device *out,
+				  int (*okfn)(struct sk_buff *))
+{
+	struct nf_conn_rtcache *rtc;
+	enum ip_conntrack_info ctinfo;
+	enum ip_conntrack_dir dir;
+	struct dst_entry *dst;
+	struct nf_conn *ct;
+	int iif;
+	u32 cookie;
+
+	if (skb_dst(skb) || skb->sk)
+		return NF_ACCEPT;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		return NF_ACCEPT;
+
+	rtc = nf_ct_rtcache_find_usable(ct);
+	if (!rtc)
+		return NF_ACCEPT;
+
+	/* if iif changes, don't use cache and let ip stack
+	 * do route lookup.
+	 *
+	 * If rp_filter is enabled it might toss skb, so
+	 * we don't want to avoid these checks.
+	 */
+	dir = CTINFO2DIR(ctinfo);
+	iif = nf_conn_rtcache_iif_get(rtc, dir);
+	if (in->ifindex != iif) {
+		pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
+			 ct, iif, in->ifindex);
+		return NF_ACCEPT;
+	}
+	dst = nf_conn_rtcache_dst_get(rtc, dir);
+	if (dst == NULL)
+		return NF_ACCEPT;
+
+	cookie = nf_rtcache_get_cookie(ops->pf, dst);
+
+	dst = dst_check(dst, cookie);
+	pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
+	if (likely(dst))
+		skb_dst_set_noref_force(skb, dst);
+	else
+		nf_conn_rtcache_dst_obsolete(rtc, dir);
+
+	return NF_ACCEPT;
+}
+
+static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops,
+				       struct sk_buff *skb,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	struct nf_conn_rtcache *rtc;
+	enum ip_conntrack_info ctinfo;
+	enum ip_conntrack_dir dir;
+	struct nf_conn *ct;
+	int iif;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		return NF_ACCEPT;
+
+	if (!nf_ct_is_confirmed(ct)) {
+		if (WARN_ON(nf_ct_rtcache_find(ct)))
+			return NF_ACCEPT;
+		nf_ct_rtcache_ext_add(ct);
+		return NF_ACCEPT;
+	}
+
+	rtc = nf_ct_rtcache_find_usable(ct);
+	if (!rtc)
+		return NF_ACCEPT;
+
+	dir = CTINFO2DIR(ctinfo);
+	iif = nf_conn_rtcache_iif_get(rtc, dir);
+	pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
+		 ct, skb, dir, iif, in->ifindex);
+	if (likely(in->ifindex == iif))
+		return NF_ACCEPT;
+
+	nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, in->ifindex);
+	return NF_ACCEPT;
+}
+
+static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
+{
+	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+	struct net_device *dev = data;
+
+	if (!rtc)
+		return 0;
+
+	if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
+	    dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
+		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
+		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
+	}
+
+	return 0;
+}
+
+static int nf_rtcache_netdev_event(struct notifier_block *this,
+				   unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct net *net = dev_net(dev);
+
+	if (event == NETDEV_DOWN)
+		nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nf_rtcache_notifier = {
+	.notifier_call = nf_rtcache_netdev_event,
+};
+
+static struct nf_hook_ops rtcache_ops[] = {
+	{
+		.hook		= nf_rtcache_in,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV4,
+		.hooknum	= NF_INET_PRE_ROUTING,
+		.priority       = NF_IP_PRI_LAST,
+	},
+	{
+		.hook           = nf_rtcache_forward,
+		.owner          = THIS_MODULE,
+		.pf             = NFPROTO_IPV4,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = NF_IP_PRI_LAST,
+	},
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
+	{
+		.hook		= nf_rtcache_in,
+		.owner		= THIS_MODULE,
+		.pf		= NFPROTO_IPV6,
+		.hooknum	= NF_INET_PRE_ROUTING,
+		.priority       = NF_IP_PRI_LAST,
+	},
+	{
+		.hook           = nf_rtcache_forward,
+		.owner          = THIS_MODULE,
+		.pf             = NFPROTO_IPV6,
+		.hooknum        = NF_INET_FORWARD,
+		.priority       = NF_IP_PRI_LAST,
+	},
+#endif
+};
+
+static struct nf_ct_ext_type rtcache_extend __read_mostly = {
+	.len	= sizeof(struct nf_conn_rtcache),
+	.align	= __alignof__(struct nf_conn_rtcache),
+	.id	= NF_CT_EXT_RTCACHE,
+	.destroy = nf_conn_rtcache_destroy,
+};
+
+static int __init nf_conntrack_rtcache_init(void)
+{
+	int ret = nf_ct_extend_register(&rtcache_extend);
+
+	if (ret < 0) {
+		pr_err("nf_conntrack_rtcache: Unable to register extension\n");
+		return ret;
+	}
+
+	ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+	if (ret < 0) {
+		nf_ct_extend_unregister(&rtcache_extend);
+		return ret;
+	}
+
+	ret = register_netdevice_notifier(&nf_rtcache_notifier);
+	if (ret) {
+		nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+		nf_ct_extend_unregister(&rtcache_extend);
+	}
+
+	return ret;
+}
+
+static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
+{
+	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
+
+	return rtc != NULL;
+}
+
+static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
+{
+	bool wait = false;
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct nf_conntrack_tuple_hash *h;
+		struct hlist_nulls_node *n;
+		struct nf_conn *ct;
+		struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+		rcu_read_lock();
+		spin_lock_bh(&pcpu->lock);
+
+		hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
+			ct = nf_ct_tuplehash_to_ctrack(h);
+			if (nf_ct_rtcache_find(ct) != NULL) {
+				wait = true;
+				break;
+			}
+		}
+		spin_unlock_bh(&pcpu->lock);
+		rcu_read_unlock();
+	}
+
+	return wait;
+}
+
+static void __exit nf_conntrack_rtcache_fini(void)
+{
+	struct net *net;
+	int count = 0;
+
+	/* remove hooks so no new connections get rtcache extension */
+	nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
+
+	synchronize_net();
+
+	unregister_netdevice_notifier(&nf_rtcache_notifier);
+
+	rtnl_lock();
+
+	/* zap all conntracks with rtcache extension */
+	for_each_net(net)
+		nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
+
+	for_each_net(net) {
+		/* .. and make sure they're gone from dying list, too */
+		while (nf_conntrack_rtcache_wait_for_dying(net)) {
+			msleep(200);
+			WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
+		}
+	}
+
+	rtnl_unlock();
+	synchronize_net();
+	nf_ct_extend_unregister(&rtcache_extend);
+}
+module_init(nf_conntrack_rtcache_init);
+module_exit(nf_conntrack_rtcache_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Conntrack route cache extension");
-- 
2.0.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH nf-next 2/2] netfilter: use conntrack rtcache if available
  2014-12-08 15:36 [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Florian Westphal
  2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
@ 2014-12-08 15:36 ` Florian Westphal
  2014-12-10 14:13 ` [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Pablo Neira Ayuso
  2 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2014-12-08 15:36 UTC (permalink / raw)
  To: netfilter-devel; +Cc: netdev, brouer, Florian Westphal

skip the reverse lookup if the iif matches the cached one.
In this case we know that a previous rpfilter check did not result
in packet drop.

This shortcut only works if rtcache is available and rule is placed
in mangle table (raw table is too early; skb->nfct will not be set).

While it would be possible to enforce rtcache, it would a)
force a dependency on conntrack and b) break backwards compatibility
since we'd have to restrict it to mangle table.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/netfilter/nf_conntrack_rtcache.h | 12 +++++++++++
 net/ipv4/netfilter/ipt_rpfilter.c            |  4 +++-
 net/ipv6/netfilter/ip6t_rpfilter.c           |  4 +++-
 net/netfilter/core.c                         | 30 ++++++++++++++++++++++++++++
 4 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_rtcache.h b/include/net/netfilter/nf_conntrack_rtcache.h
index e2fb302..19265ad 100644
--- a/include/net/netfilter/nf_conntrack_rtcache.h
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
@@ -27,6 +27,18 @@ struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
 #endif
 }
 
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+bool nf_conn_rtcache_match_dev(const struct sk_buff *skb,
+			       const struct net_device *dev);
+#else
+static inline bool
+nf_conn_rtcache_match_dev(const struct sk_buff *skb,
+			  const struct net_device *dev)
+{
+	return false;
+}
+#endif
+
 static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
 					  enum ip_conntrack_dir dir)
 {
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index 4bfaedf..f39e934 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -19,6 +19,8 @@
 #include <linux/netfilter/xt_rpfilter.h>
 #include <linux/netfilter/x_tables.h>
 
+#include <net/netfilter/nf_conntrack_rtcache.h>
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
 MODULE_DESCRIPTION("iptables: ipv4 reverse path filter match");
@@ -82,7 +84,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
 	info = par->matchinfo;
 	invert = info->flags & XT_RPFILTER_INVERT;
 
-	if (rpfilter_is_local(skb))
+	if (rpfilter_is_local(skb) || nf_conn_rtcache_match_dev(skb, par->in))
 		return true ^ invert;
 
 	iph = ip_hdr(skb);
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
index 790e0c6..8db9fe7 100644
--- a/net/ipv6/netfilter/ip6t_rpfilter.c
+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
@@ -16,6 +16,8 @@
 #include <linux/netfilter/xt_rpfilter.h>
 #include <linux/netfilter/x_tables.h>
 
+#include <net/netfilter/nf_conntrack_rtcache.h>
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
 MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match");
@@ -85,7 +87,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
 	struct ipv6hdr *iph;
 	bool invert = info->flags & XT_RPFILTER_INVERT;
 
-	if (rpfilter_is_local(skb))
+	if (rpfilter_is_local(skb) || nf_conn_rtcache_match_dev(skb, par->in))
 		return true ^ invert;
 
 	iph = ipv6_hdr(skb);
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index fea9ef5..651b4c6 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -25,6 +25,8 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 
+#include <net/netfilter/nf_conntrack_rtcache.h>
+
 #include "nf_internals.h"
 
 static DEFINE_MUTEX(afinfo_mutex);
@@ -267,6 +269,34 @@ EXPORT_SYMBOL_GPL(nfq_ct_hook);
 struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook __read_mostly;
 EXPORT_SYMBOL_GPL(nfq_ct_nat_hook);
 
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
+/* returns true if dev matches the last recorded
+ * input interface of the conntrack attached to skb.
+ *
+ * This is not in conntrack to avoid module dependency.
+ */
+bool nf_conn_rtcache_match_dev(const struct sk_buff *skb,
+			       const struct net_device *dev)
+{
+	struct nf_conn_rtcache *rtc;
+	enum ip_conntrack_info ctinfo;
+	enum ip_conntrack_dir dir;
+	struct nf_conn *ct;
+	int iif;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	rtc = nf_ct_rtcache_find(ct);
+	if (!rtc)
+		return false;
+
+	dir = CTINFO2DIR(ctinfo);
+	iif = nf_conn_rtcache_iif_get(rtc, dir);
+
+	return iif == dev->ifindex;
+}
+EXPORT_SYMBOL_GPL(nf_conn_rtcache_match_dev);
+#endif
+
 #endif /* CONFIG_NF_CONNTRACK */
 
 #ifdef CONFIG_NF_NAT_NEEDED
-- 
2.0.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH nf-next 1/2] netfilter: conntrack: cache route for forwarded connections
  2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
@ 2014-12-08 22:33   ` Florian Westphal
  2016-04-28  8:05   ` [nf-next, " Charlemagne Lasse
  1 sibling, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2014-12-08 22:33 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, netdev, brouer

Florian Westphal <fw@strlen.de> wrote:
> +	if (likely(dst))
> +		skb_dst_set_noref_force(skb, dst);

Note that Hannes submitted a patch vs. net-next that removes
skb_dst_set_noref_force().

So depending on the oder in which the patches are applied
(iff they are...) the above should read

skb_dst_set_noref(skb, dst);

instead.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections
  2014-12-08 15:36 [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Florian Westphal
  2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
  2014-12-08 15:36 ` [PATCH nf-next 2/2] netfilter: use conntrack rtcache if available Florian Westphal
@ 2014-12-10 14:13 ` Pablo Neira Ayuso
  2014-12-10 14:42   ` Florian Westphal
  2 siblings, 1 reply; 7+ messages in thread
From: Pablo Neira Ayuso @ 2014-12-10 14:13 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, netdev, brouer, Eric Dumazet

On Mon, Dec 08, 2014 at 04:36:02PM +0100, Florian Westphal wrote:
> [ Pablo, in case you deem this too late for -next just let me know
> and I will resend once its open again ]
> 
> This adds an optional forward routing cache extension for netfilter
> connection tracking.
> 
> The memory cost is an additional 32 bytes per conntrack entry
> on x86_64.
> 
> Unlike any other currently implemented connection tracking
> extension the rtcache has no run-time tunables, it is always active.
> 
> Also, unlike other conntrack extensions, it can be built as a module,
> in this case modprobe/rmmod are used to enable/disable the cache.

I expect distributors will provide this a module. I think we should
provide features that can be enable/disable in some way, in this case
it can be modprobe/rmmod.

BTW, did you evaluate Eric's alternative? Any comment on that?

Florian Westphal <fw@strlen.de> wrote:
>> +     if (likely(dst))
>> +             skb_dst_set_noref_force(skb, dst);
>
> Note that Hannes submitted a patch vs. net-next that removes
> skb_dst_set_noref_force().

I refreshed the nf-next tree, this patch is now there.

If the merge window remains open, I'll take the pending patches in
patchwork and send a new batch for David by tomorrow morning.

Let me know, thanks.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections
  2014-12-10 14:13 ` [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Pablo Neira Ayuso
@ 2014-12-10 14:42   ` Florian Westphal
  0 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2014-12-10 14:42 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Florian Westphal, netfilter-devel, netdev, brouer, Eric Dumazet

Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Mon, Dec 08, 2014 at 04:36:02PM +0100, Florian Westphal wrote:
> > [ Pablo, in case you deem this too late for -next just let me know
> > and I will resend once its open again ]
> > 
> > This adds an optional forward routing cache extension for netfilter
> > connection tracking.
> > 
> > The memory cost is an additional 32 bytes per conntrack entry
> > on x86_64.
> > 
> > Unlike any other currently implemented connection tracking
> > extension the rtcache has no run-time tunables, it is always active.
> > 
> > Also, unlike other conntrack extensions, it can be built as a module,
> > in this case modprobe/rmmod are used to enable/disable the cache.
> 
> I expect distributors will provide this a module. I think we should
> provide features that can be enable/disable in some way, in this case
> it can be modprobe/rmmod.

Yes, I just wanted to mention this in case someone thinks a sysctl is
must-have.

I did not want to add sysctl "just because" as we cannot easily rip
them out later.

> BTW, did you evaluate Eric's alternative? Any comment on that?

Right, sorry.  So Eric suggested to leverage existing early demux.

This would work, but I found several disadvantages, namely it would:

1. only work for protocols that have early demux support
2. have to add some sort of new mini-sk to the "right" data
structure (udp_table, tcp_hashinfo) so not just af but l4 specific
handling
3. add more code to L4 protocol handlers
4. add some upper ceiling for such "forward sockets".
5. devise a scheme by which to zap the entry again

4+5 can be avoided by embedding the "forward sock" inside conntrack,
but that would mean we get larger code than this patch while still
retaining the conntrack dependency.

And without conntrack, I'm not sure how one would go about
adding such route cache without adding back all the problems it had.

> If the merge window remains open, I'll take the pending patches in
> patchwork and send a new batch for David by tomorrow morning.
> 
> Let me know, thanks.

Ok.  I can send a rebased V3.  OTOH, I don't want to rush things.

If you think further discussion is needed before deciding to go with
a conntrack-based route cache then lets do that.

In this case I can resend the v3 once next is open again plus a summary
of the alternatives/problems and we can take it from there.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [nf-next, 1/2] netfilter: conntrack: cache route for forwarded connections
  2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
  2014-12-08 22:33   ` Florian Westphal
@ 2016-04-28  8:05   ` Charlemagne Lasse
  1 sibling, 0 replies; 7+ messages in thread
From: Charlemagne Lasse @ 2016-04-28  8:05 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, netdev, brouer, davem

2014-12-08 16:36 GMT+01:00 Florian Westphal <fw@strlen.de>:
> ... to avoid per-packet FIB lookup if possible.
>
> The cached dst is re-used provided the input interface
> is the same as that of the previous packet in the same direction.
>
> If not, the cached dst is invalidated.

It looks like someone found out that this patch causes crashes. This
was reported to OpenWrt in ticket https://dev.openwrt.org/ticket/22283

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-04-28  8:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-08 15:36 [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Florian Westphal
2014-12-08 15:36 ` [PATCH nf-next 1/2] netfilter: conntrack: cache route " Florian Westphal
2014-12-08 22:33   ` Florian Westphal
2016-04-28  8:05   ` [nf-next, " Charlemagne Lasse
2014-12-08 15:36 ` [PATCH nf-next 2/2] netfilter: use conntrack rtcache if available Florian Westphal
2014-12-10 14:13 ` [PATCH nf-next 0/2] netfilter: conntrack: route cache for forwarded connections Pablo Neira Ayuso
2014-12-10 14:42   ` Florian Westphal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.