root/net/core/dst_cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dst_cache_per_cpu_dst_set
  2. dst_cache_per_cpu_get
  3. dst_cache_get
  4. dst_cache_get_ip4
  5. dst_cache_set_ip4
  6. dst_cache_set_ip6
  7. dst_cache_get_ip6
  8. dst_cache_init
  9. dst_cache_destroy

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * net/core/dst_cache.c - dst entry cache
   4  *
   5  * Copyright (c) 2016 Paolo Abeni <pabeni@redhat.com>
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/percpu.h>
  10 #include <net/dst_cache.h>
  11 #include <net/route.h>
  12 #if IS_ENABLED(CONFIG_IPV6)
  13 #include <net/ip6_fib.h>
  14 #endif
  15 #include <uapi/linux/in.h>
  16 
  17 struct dst_cache_pcpu {
  18         unsigned long refresh_ts;
  19         struct dst_entry *dst;
  20         u32 cookie;
  21         union {
  22                 struct in_addr in_saddr;
  23                 struct in6_addr in6_saddr;
  24         };
  25 };
  26 
  27 static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
  28                                       struct dst_entry *dst, u32 cookie)
  29 {
  30         dst_release(dst_cache->dst);
  31         if (dst)
  32                 dst_hold(dst);
  33 
  34         dst_cache->cookie = cookie;
  35         dst_cache->dst = dst;
  36 }
  37 
  38 static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
  39                                                struct dst_cache_pcpu *idst)
  40 {
  41         struct dst_entry *dst;
  42 
  43         dst = idst->dst;
  44         if (!dst)
  45                 goto fail;
  46 
  47         /* the cache already hold a dst reference; it can't go away */
  48         dst_hold(dst);
  49 
  50         if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) ||
  51                      (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
  52                 dst_cache_per_cpu_dst_set(idst, NULL, 0);
  53                 dst_release(dst);
  54                 goto fail;
  55         }
  56         return dst;
  57 
  58 fail:
  59         idst->refresh_ts = jiffies;
  60         return NULL;
  61 }
  62 
  63 struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
  64 {
  65         if (!dst_cache->cache)
  66                 return NULL;
  67 
  68         return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
  69 }
  70 EXPORT_SYMBOL_GPL(dst_cache_get);
  71 
  72 struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
  73 {
  74         struct dst_cache_pcpu *idst;
  75         struct dst_entry *dst;
  76 
  77         if (!dst_cache->cache)
  78                 return NULL;
  79 
  80         idst = this_cpu_ptr(dst_cache->cache);
  81         dst = dst_cache_per_cpu_get(dst_cache, idst);
  82         if (!dst)
  83                 return NULL;
  84 
  85         *saddr = idst->in_saddr.s_addr;
  86         return container_of(dst, struct rtable, dst);
  87 }
  88 EXPORT_SYMBOL_GPL(dst_cache_get_ip4);
  89 
  90 void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
  91                        __be32 saddr)
  92 {
  93         struct dst_cache_pcpu *idst;
  94 
  95         if (!dst_cache->cache)
  96                 return;
  97 
  98         idst = this_cpu_ptr(dst_cache->cache);
  99         dst_cache_per_cpu_dst_set(idst, dst, 0);
 100         idst->in_saddr.s_addr = saddr;
 101 }
 102 EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
 103 
 104 #if IS_ENABLED(CONFIG_IPV6)
 105 void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
 106                        const struct in6_addr *saddr)
 107 {
 108         struct dst_cache_pcpu *idst;
 109 
 110         if (!dst_cache->cache)
 111                 return;
 112 
 113         idst = this_cpu_ptr(dst_cache->cache);
 114         dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
 115                                   rt6_get_cookie((struct rt6_info *)dst));
 116         idst->in6_saddr = *saddr;
 117 }
 118 EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
 119 
 120 struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
 121                                     struct in6_addr *saddr)
 122 {
 123         struct dst_cache_pcpu *idst;
 124         struct dst_entry *dst;
 125 
 126         if (!dst_cache->cache)
 127                 return NULL;
 128 
 129         idst = this_cpu_ptr(dst_cache->cache);
 130         dst = dst_cache_per_cpu_get(dst_cache, idst);
 131         if (!dst)
 132                 return NULL;
 133 
 134         *saddr = idst->in6_saddr;
 135         return dst;
 136 }
 137 EXPORT_SYMBOL_GPL(dst_cache_get_ip6);
 138 #endif
 139 
 140 int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
 141 {
 142         dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu,
 143                                             gfp | __GFP_ZERO);
 144         if (!dst_cache->cache)
 145                 return -ENOMEM;
 146 
 147         dst_cache_reset(dst_cache);
 148         return 0;
 149 }
 150 EXPORT_SYMBOL_GPL(dst_cache_init);
 151 
 152 void dst_cache_destroy(struct dst_cache *dst_cache)
 153 {
 154         int i;
 155 
 156         if (!dst_cache->cache)
 157                 return;
 158 
 159         for_each_possible_cpu(i)
 160                 dst_release(per_cpu_ptr(dst_cache->cache, i)->dst);
 161 
 162         free_percpu(dst_cache->cache);
 163 }
 164 EXPORT_SYMBOL_GPL(dst_cache_destroy);

/* [<][>][^][v][top][bottom][index][help] */