aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaurabh <saurabh.mohan@vyatta.com>2012-07-17 05:44:49 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-18 12:36:12 -0400
commiteb8637cd4a0d651cf4fcc1559231facee829a0ac (patch)
treeb9e8259314c4967b9b89930fdb00186ab401444e
parentfcc24db5e8a75ed3ce2238f4ad1b3bef8634f7e1 (diff)
net/ipv4: VTI support rx-path hook in xfrm4_mode_tunnel.
Incorporated David and Steffen's comments. Add hook for rx-path xfmr4_mode_tunnel for VTI tunnel module. Signed-off-by: Saurabh Mohan <saurabh.mohan@vyatta.com> Reviewed-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/xfrm.h2
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c68
2 files changed, 70 insertions, 0 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 17acbc92476d..d9509eb29b80 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1475,6 +1475,8 @@ extern int xfrm4_output(struct sk_buff *skb);
1475extern int xfrm4_output_finish(struct sk_buff *skb); 1475extern int xfrm4_output_finish(struct sk_buff *skb);
1476extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); 1476extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
1477extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); 1477extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
1478extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler);
1479extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler);
1478extern int xfrm6_extract_header(struct sk_buff *skb); 1480extern int xfrm6_extract_header(struct sk_buff *skb);
1479extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1481extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
1480extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); 1482extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index ed4bf11ef9f4..ddee0a099a2c 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -15,6 +15,65 @@
15#include <net/ip.h> 15#include <net/ip.h>
16#include <net/xfrm.h> 16#include <net/xfrm.h>
17 17
18/* Informational hook. The decap is still done here. */
19static struct xfrm_tunnel __rcu *rcv_notify_handlers __read_mostly;
20static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex);
21
22int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler)
23{
24 struct xfrm_tunnel __rcu **pprev;
25 struct xfrm_tunnel *t;
26 int ret = -EEXIST;
27 int priority = handler->priority;
28
29 mutex_lock(&xfrm4_mode_tunnel_input_mutex);
30
31 for (pprev = &rcv_notify_handlers;
32 (t = rcu_dereference_protected(*pprev,
33 lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
34 pprev = &t->next) {
35 if (t->priority > priority)
36 break;
37 if (t->priority == priority)
38 goto err;
39
40 }
41
42 handler->next = *pprev;
43 rcu_assign_pointer(*pprev, handler);
44
45 ret = 0;
46
47err:
48 mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
49 return ret;
50}
51EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register);
52
53int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler)
54{
55 struct xfrm_tunnel __rcu **pprev;
56 struct xfrm_tunnel *t;
57 int ret = -ENOENT;
58
59 mutex_lock(&xfrm4_mode_tunnel_input_mutex);
60 for (pprev = &rcv_notify_handlers;
61 (t = rcu_dereference_protected(*pprev,
62 lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
63 pprev = &t->next) {
64 if (t == handler) {
65 *pprev = handler->next;
66 ret = 0;
67 break;
68 }
69 }
70 mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
71 synchronize_net();
72
73 return ret;
74}
75EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister);
76
18static inline void ipip_ecn_decapsulate(struct sk_buff *skb) 77static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
19{ 78{
20 struct iphdr *inner_iph = ipip_hdr(skb); 79 struct iphdr *inner_iph = ipip_hdr(skb);
@@ -64,8 +123,14 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
64 return 0; 123 return 0;
65} 124}
66 125
126#define for_each_input_rcu(head, handler) \
127 for (handler = rcu_dereference(head); \
128 handler != NULL; \
129 handler = rcu_dereference(handler->next))
130
67static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 131static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
68{ 132{
133 struct xfrm_tunnel *handler;
69 int err = -EINVAL; 134 int err = -EINVAL;
70 135
71 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) 136 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -74,6 +139,9 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
74 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 139 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
75 goto out; 140 goto out;
76 141
142 for_each_input_rcu(rcv_notify_handlers, handler)
143 handler->handler(skb);
144
77 if (skb_cloned(skb) && 145 if (skb_cloned(skb) &&
78 (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) 146 (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
79 goto out; 147 goto out;