net/ipv4: VTI support rx-path hook in xfrm4_mode_tunnel.
authorSaurabh <saurabh.mohan@vyatta.com>
Tue, 17 Jul 2012 09:44:49 +0000 (09:44 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Jul 2012 16:36:12 +0000 (09:36 -0700)
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>
include/net/xfrm.h
net/ipv4/xfrm4_mode_tunnel.c

index 17acbc92476d78263affd3fe338fb94faab36982..d9509eb29b80f989eb47531877279ae93f31f85c 100644 (file)
@@ -1475,6 +1475,8 @@ extern int xfrm4_output(struct sk_buff *skb);
 extern int xfrm4_output_finish(struct sk_buff *skb);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
+extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler);
+extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler);
 extern int xfrm6_extract_header(struct sk_buff *skb);
 extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
index ed4bf11ef9f4709b9418ebeff06789c9b84b77ab..ddee0a099a2c8caea19ccabbd957032f59896fdd 100644 (file)
 #include <net/ip.h>
 #include <net/xfrm.h>
 
+/* Informational hook. The decap is still done here. */
+static struct xfrm_tunnel __rcu *rcv_notify_handlers __read_mostly;
+static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex);
+
+int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler)
+{
+       struct xfrm_tunnel __rcu **pprev;
+       struct xfrm_tunnel *t;
+       int ret = -EEXIST;
+       int priority = handler->priority;
+
+       mutex_lock(&xfrm4_mode_tunnel_input_mutex);
+
+       for (pprev = &rcv_notify_handlers;
+            (t = rcu_dereference_protected(*pprev,
+            lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t->priority > priority)
+                       break;
+               if (t->priority == priority)
+                       goto err;
+
+       }
+
+       handler->next = *pprev;
+       rcu_assign_pointer(*pprev, handler);
+
+       ret = 0;
+
+err:
+       mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register);
+
+int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler)
+{
+       struct xfrm_tunnel __rcu **pprev;
+       struct xfrm_tunnel *t;
+       int ret = -ENOENT;
+
+       mutex_lock(&xfrm4_mode_tunnel_input_mutex);
+       for (pprev = &rcv_notify_handlers;
+            (t = rcu_dereference_protected(*pprev,
+            lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t == handler) {
+                       *pprev = handler->next;
+                       ret = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
+       synchronize_net();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister);
+
 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
 {
        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)
        return 0;
 }
 
+#define for_each_input_rcu(head, handler)      \
+       for (handler = rcu_dereference(head);   \
+            handler != NULL;                   \
+            handler = rcu_dereference(handler->next))
+
 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
+       struct xfrm_tunnel *handler;
        int err = -EINVAL;
 
        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)
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto out;
 
+       for_each_input_rcu(rcv_notify_handlers, handler)
+               handler->handler(skb);
+
        if (skb_cloned(skb) &&
            (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
                goto out;