[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20120903211602.8851.2843.stgit@dragon>
Date: Mon, 03 Sep 2012 23:16:26 +0200
From: Jesper Dangaard Brouer <brouer@...hat.com>
To: "Patrick McHardy" <kaber@...sh.net>,
Hans Schillstrom <hans@...illstrom.com>,
Hans Schillstrom <hans.schillstrom@...csson.com>
Cc: Jesper Dangaard Brouer <brouer@...hat.com>, netdev@...r.kernel.org,
netfilter-devel@...r.kernel.org,
Pablo Neira Ayuso <pablo@...filter.org>
Subject: [RFC PATCH 1/2] net: Cache IPv6 extension header "skip" parsing
Store IPv6 exthdr data from ipv6_find_hdr() in skb->cb[].
Introducing struct inet6_skb_exthdr_cache / IP6CB_EXTHDR, as its not
possible to extend inet6_skb_parm directly, or else DCCP dccp_skb_cb
CB size gets too big.
Adding:
__u16 thoff; /* L4 Transport Header offset */
__s16 protocol;/* L4 protocol */
__u16 fragoff; /* packet is a fragment, with offset */
Optimize ip6t_do_table() by using the new ipv6_find_hdr_cb() in
ip6_packet_match(). Before ipv6_find_hdr() were called for each
iptables rule, with a "-p" protocol option (including -p all), which
is very commonly used. The function ipv6_find_hdr_cb() is inlined to
optimize this case and avoid a function call.
The inet6_skb_exthdr_cache / IP6CB_EXTHDR is added to linux/ipv6.h in
the hope that ipv6_skip_exthdr() might also take advantage of this, in
the future.
Signed-off-by: Jesper Dangaard Brouer <brouer@...hat.com>
---
Can someone tell me if netfilter (with all of its different HOOKs) can be
allowed to modify data after inet6_skb_parm/IP6CB ???
include/linux/ipv6.h | 15 +++++++++++
include/linux/netfilter_ipv6/ip6_tables.h | 40 +++++++++++++++++++++++++++++
net/ipv6/netfilter/ip6_tables.c | 2 +
3 files changed, 56 insertions(+), 1 deletions(-)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 0b94e91..21d8cc3 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -266,6 +266,21 @@ struct inet6_skb_parm {
#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb))
#define IP6CBMTU(skb) ((struct ip6_mtuinfo *)((skb)->cb))
+/* Caching of exthdr info
+ * - This is used by netfilter and IPVS.
+ * (cannot extend inet6_skb_parm directly due to DCCP CB size gets too big)
+ */
+struct inet6_skb_exthdr_cache {
+ union {
+ struct inet6_skb_parm h6;
+ } header;
+ /* Caching IPv6 exthdr "skip" info */
+ __u16 thoff; /* L4 Transport Header offset */
+ __s16 protocol;/* L4 protocol */
+ __u16 fragoff; /* packet is a fragment, with offset */
+};
+#define IP6CB_EXTHDR(skb) ((struct inet6_skb_exthdr_cache*)((skb)->cb))
+
static inline int inet6_iif(const struct sk_buff *skb)
{
return IP6CB(skb)->iif;
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 08c2cbb..5209aff 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -303,6 +303,46 @@ enum {
IP6T_FH_F_AUTH = (1 << 1),
};
+/* Function caches IPv6 exthdr data from ipv6_find_hdr() in skb->cb[]
+ * - uses inet6_skb_exthdr_cache / IP6CB_EXTHDR
+ */
+static inline int
+ipv6_find_hdr_cb(const struct sk_buff *skb, unsigned int *offset,
+ int target, unsigned short *fragoff, int *flags)
+{
+ struct inet6_skb_exthdr_cache *exthdr_cache = IP6CB_EXTHDR(skb);
+ __s16 protocol;
+
+ /* Only cache the "skip" exthdr usage */
+ if (target > 0) /* looking for a specific nexthdr target */
+ goto no_cache;
+ if (*offset) /* start at a specific offset */
+ goto no_cache;
+ if (flags) /* not caching flags at the moment */
+ goto no_cache;
+
+ /* Use thoff (transport header) as cache avail indicator */
+ if (exthdr_cache->thoff > 0) {
+ *offset = exthdr_cache->thoff;
+ protocol = exthdr_cache->protocol;
+ if (fragoff)
+ *fragoff = exthdr_cache->fragoff;
+ return protocol;
+ }
+
+ protocol = ipv6_find_hdr(skb, offset, target, fragoff, flags);
+ if (protocol > 0) {
+ /* save a copy in the CB */
+ exthdr_cache->thoff = *offset;
+ exthdr_cache->protocol = protocol;
+ if (fragoff)
+ exthdr_cache->fragoff = *fragoff;
+ }
+ return protocol;
+no_cache:
+ return ipv6_find_hdr(skb, offset, target, fragoff, flags);
+}
+
/* find specified header and get offset to it */
extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff, int *fragflg);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index d7cb045..79367f2 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -133,7 +133,7 @@ ip6_packet_match(const struct sk_buff *skb,
int protohdr;
unsigned short _frag_off;
- protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
+ protohdr = ipv6_find_hdr_cb(skb, protoff, -1, &_frag_off, NULL);
if (protohdr < 0) {
if (_frag_off == 0)
*hotdrop = true;
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists