netfilter: conntrack: route cache for forwarded connections
Subsystems (3)
Florian Westphal
maintainercover netfilter: conntrack: route cache for forwarded connections
[ 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.
Florian Westphal
maintainerPATCH 1/2 netfilter: conntrack: cache route for forwarded connections
... 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.
---
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
include/net/netfilter/nf_conntrack_extend.h +4 -0
@@ -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 {
include/net/netfilter/nf_conntrack_rtcache.h new file +34 -0
@@ -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; +}
net/netfilter/Kconfig +12 -0
@@ -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
net/netfilter/Makefile +3 -0
@@ -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
net/netfilter/nf_conntrack_rtcache.c new file +387 -0
387 lines not on this page · raw message
Signature · 1 line
2.0.4
Florian Westphal
maintainerRe: [PATCH nf-next 1/2] netfilter: conntrack: cache route for forwarded connections
net/netfilter/nf_conntrack_rtcache.c line 175
Quoted 2 lines · Florian Westphal
net/netfilter/nf_conntrack_rtcache.c new file +2
-0+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.
Re: [nf-next, 1/2] netfilter: conntrack: cache route for forwarded connections
In reply to Florian Westphal2014-12-08 16:36 GMT+01:00 Florian Westphal <[email protected]>:
Quoted 6 lines
... 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
Florian Westphal
maintainerPATCH 2/2 netfilter: use conntrack rtcache if available
In reply to Florian Westphalskip 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.
--- 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(-)
include/net/netfilter/nf_conntrack_rtcache.h +12 -0
@@ -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) {
net/ipv4/netfilter/ipt_rpfilter.c +3 -1
@@ -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 <[email protected]>" );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);
net/ipv6/netfilter/ip6t_rpfilter.c +3 -1
@@ -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 <[email protected]>" );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);
net/netfilter/core.c +30 -0
@@ -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
Signature · 1 line
2.0.4
Pablo Neira Ayuso
maintainerQuoted 6 lines · Florian Westphal
[ 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.
Quoted 8 lines
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?
Quoted 5 lines · Florian Westphal
Review
Quoted 2 lines
(quoted diff) +2
-0+ 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.
Florian Westphal
maintainerQuoted 13 lines · Pablo Neira Ayuso
Quoted 12 lines · Florian Westphal
[ 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.
Quoted 6 lines
Quoted 2 lines
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.
Quoted 1 line
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.
Quoted 4 lines
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.