Destination caching on a per-tunnel basis is a performance win, so we
enable this unconditionally for the module.

Signed-off-by: Jonas Bonn <jo...@norrbonn.se>
---
 drivers/net/Kconfig |  1 +
 drivers/net/gtp.c   | 27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 260f9f46668b..f79277222125 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -276,6 +276,7 @@ config GTP
        tristate "GPRS Tunneling Protocol datapath (GTP-U)"
        depends on INET
        select NET_UDP_TUNNEL
+       select DST_CACHE
        help
          This allows one to create gtp virtual interfaces that provide
          the GPRS Tunneling Protocol datapath (GTP-U). This tunneling protocol
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 40bbbe8cfad6..6708738681d2 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -64,6 +64,8 @@ struct pdp_ctx {
        struct sock             *sk;
        struct net_device       *dev;
 
+       struct dst_cache dst_cache;
+
        atomic_t                tx_seq;
        struct rcu_head         rcu_head;
 };
@@ -577,9 +579,15 @@ static struct rtable *gtp_get_v4_rt(struct sk_buff *skb,
                                    __be32 *saddr)
 {
        const struct sock *sk = pctx->sk;
+       struct dst_cache *dst_cache;
        struct rtable *rt = NULL;
        struct flowi4 fl4;
 
+       dst_cache = (struct dst_cache *)&pctx->dst_cache;
+       rt = dst_cache_get_ip4(dst_cache, saddr);
+       if (rt)
+               return rt;
+
        memset(&fl4, 0, sizeof(fl4));
        fl4.flowi4_oif          = sk->sk_bound_dev_if;
        fl4.daddr               = ipv4(&pctx->peer_addr);
@@ -600,6 +608,8 @@ static struct rtable *gtp_get_v4_rt(struct sk_buff *skb,
 
        *saddr = fl4.saddr;
 
+       dst_cache_set_ip4(dst_cache, &rt->dst, *saddr);
+
        return rt;
 }
 
@@ -610,8 +620,14 @@ static struct dst_entry *gtp_get_v6_dst(struct sk_buff 
*skb,
 {
        const struct sock *sk = pctx->sk;
        struct dst_entry *dst = NULL;
+       struct dst_cache *dst_cache;
        struct flowi6 fl6;
 
+       dst_cache = (struct dst_cache *)&pctx->dst_cache;
+       dst = dst_cache_get_ip6(dst_cache, saddr);
+       if (dst)
+               return dst;
+
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_mark = skb->mark;
        fl6.flowi6_proto = IPPROTO_UDP;
@@ -630,6 +646,8 @@ static struct dst_entry *gtp_get_v6_dst(struct sk_buff *skb,
 
        *saddr = fl6.saddr;
 
+       dst_cache_set_ip6(dst_cache, dst, saddr);
+
        return dst;
 }
 
@@ -1236,6 +1254,8 @@ static void pdp_fill(struct pdp_ctx *pctx, struct 
genl_info *info)
        pctx->gtp_version = nla_get_u32(info->attrs[GTPA_VERSION]);
        pctx->flags = 0;
 
+       dst_cache_reset(&pctx->dst_cache);
+
        if (info->attrs[GTPA_PEER_IPV6]) {
                pctx->flags |= PDP_F_PEER_V6;
                pctx->peer_addr = nla_get_in6_addr(info->attrs[GTPA_PEER_IPV6]);
@@ -1331,6 +1351,11 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, 
struct sock *sk,
        if (pctx == NULL)
                return ERR_PTR(-ENOMEM);
 
+       if (dst_cache_init(&pctx->dst_cache, GFP_ATOMIC)) {
+               kfree(pctx);
+               return ERR_PTR(-ENOBUFS);
+       }
+
        sock_hold(sk);
        pctx->sk = sk;
        pctx->dev = gtp->dev;
@@ -1374,6 +1399,8 @@ static void pdp_context_free(struct rcu_head *head)
 {
        struct pdp_ctx *pctx = container_of(head, struct pdp_ctx, rcu_head);
 
+       dst_cache_destroy(&pctx->dst_cache);
+
        sock_put(pctx->sk);
        kfree(pctx);
 }
-- 
2.27.0

Reply via email to