diff options
author | Saurabh <saurabh.mohan@vyatta.com> | 2012-07-17 05:44:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-18 12:36:12 -0400 |
commit | eb8637cd4a0d651cf4fcc1559231facee829a0ac (patch) | |
tree | b9e8259314c4967b9b89930fdb00186ab401444e | |
parent | fcc24db5e8a75ed3ce2238f4ad1b3bef8634f7e1 (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.h | 2 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 68 |
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); | |||
1475 | extern int xfrm4_output_finish(struct sk_buff *skb); | 1475 | extern int xfrm4_output_finish(struct sk_buff *skb); |
1476 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); | 1476 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); |
1477 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); | 1477 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); |
1478 | extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler); | ||
1479 | extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler); | ||
1478 | extern int xfrm6_extract_header(struct sk_buff *skb); | 1480 | extern int xfrm6_extract_header(struct sk_buff *skb); |
1479 | extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1481 | extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1480 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); | 1482 | extern 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. */ | ||
19 | static struct xfrm_tunnel __rcu *rcv_notify_handlers __read_mostly; | ||
20 | static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex); | ||
21 | |||
22 | int 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 | |||
47 | err: | ||
48 | mutex_unlock(&xfrm4_mode_tunnel_input_mutex); | ||
49 | return ret; | ||
50 | } | ||
51 | EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register); | ||
52 | |||
53 | int 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 | } | ||
75 | EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister); | ||
76 | |||
18 | static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | 77 | static 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 | |||
67 | static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | 131 | static 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; |