Users of lwt tunnels may set up some secondary state in build_state
function. Add a corresponding destroy_state function to allow users to
clean up state. This destroy state function is called from lwstate_free.
Also, we now free lwstate using kfree_rcu so user can assume structure
is not freed before rcu.

Acked-by: Roopa Prabhu <ro...@cumulusnetworks.com>
Signed-off-by: Tom Herbert <t...@herbertland.com>
---
 include/net/lwtunnel.h |  7 +++----
 net/core/lwtunnel.c    | 13 +++++++++++++
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index ea3f80f..67d235f 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -29,6 +29,7 @@ struct lwtunnel_state {
        int             (*orig_input)(struct sk_buff *);
        int             len;
        __u16           headroom;
+       struct          rcu_head rcu;
        __u8            data[0];
 };
 
@@ -36,6 +37,7 @@ struct lwtunnel_encap_ops {
        int (*build_state)(struct net_device *dev, struct nlattr *encap,
                           unsigned int family, const void *cfg,
                           struct lwtunnel_state **ts);
+       void (*destroy_state)(struct lwtunnel_state *lws);
        int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
        int (*input)(struct sk_buff *skb);
        int (*fill_encap)(struct sk_buff *skb,
@@ -46,10 +48,7 @@ struct lwtunnel_encap_ops {
 };
 
 #ifdef CONFIG_LWTUNNEL
-static inline void lwtstate_free(struct lwtunnel_state *lws)
-{
-       kfree(lws);
-}
+void lwtstate_free(struct lwtunnel_state *lws);
 
 static inline struct lwtunnel_state *
 lwtstate_get(struct lwtunnel_state *lws)
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index e5f84c2..88fd642 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -130,6 +130,19 @@ int lwtunnel_build_state(struct net_device *dev, u16 
encap_type,
 }
 EXPORT_SYMBOL(lwtunnel_build_state);
 
+void lwtstate_free(struct lwtunnel_state *lws)
+{
+       const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type];
+
+       if (ops->destroy_state) {
+               ops->destroy_state(lws);
+               kfree_rcu(lws, rcu);
+       } else {
+               kfree(lws);
+       }
+}
+EXPORT_SYMBOL(lwtstate_free);
+
 int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate)
 {
        const struct lwtunnel_encap_ops *ops;
-- 
2.9.3

Reply via email to