root/net/core/dst.c

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

DEFINITIONS

This source file includes following definitions.
  1. dst_discard_out
  2. dst_init
  3. dst_alloc
  4. dst_destroy
  5. dst_destroy_rcu
  6. dst_dev_put
  7. dst_release
  8. dst_release_immediate
  9. dst_cow_metrics_generic
  10. __dst_destroy_metrics_generic
  11. dst_md_discard_out
  12. dst_md_discard
  13. __metadata_dst_init
  14. metadata_dst_alloc
  15. metadata_dst_free
  16. metadata_dst_alloc_percpu
  17. metadata_dst_free_percpu

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * net/core/dst.c       Protocol independent destination cache.
   4  *
   5  * Authors:             Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   6  *
   7  */
   8 
   9 #include <linux/bitops.h>
  10 #include <linux/errno.h>
  11 #include <linux/init.h>
  12 #include <linux/kernel.h>
  13 #include <linux/workqueue.h>
  14 #include <linux/mm.h>
  15 #include <linux/module.h>
  16 #include <linux/slab.h>
  17 #include <linux/netdevice.h>
  18 #include <linux/skbuff.h>
  19 #include <linux/string.h>
  20 #include <linux/types.h>
  21 #include <net/net_namespace.h>
  22 #include <linux/sched.h>
  23 #include <linux/prefetch.h>
  24 #include <net/lwtunnel.h>
  25 #include <net/xfrm.h>
  26 
  27 #include <net/dst.h>
  28 #include <net/dst_metadata.h>
  29 
  30 int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
  31 {
  32         kfree_skb(skb);
  33         return 0;
  34 }
  35 EXPORT_SYMBOL(dst_discard_out);
  36 
  37 const struct dst_metrics dst_default_metrics = {
  38         /* This initializer is needed to force linker to place this variable
  39          * into const section. Otherwise it might end into bss section.
  40          * We really want to avoid false sharing on this variable, and catch
  41          * any writes on it.
  42          */
  43         .refcnt = REFCOUNT_INIT(1),
  44 };
  45 EXPORT_SYMBOL(dst_default_metrics);
  46 
  47 void dst_init(struct dst_entry *dst, struct dst_ops *ops,
  48               struct net_device *dev, int initial_ref, int initial_obsolete,
  49               unsigned short flags)
  50 {
  51         dst->dev = dev;
  52         if (dev)
  53                 dev_hold(dev);
  54         dst->ops = ops;
  55         dst_init_metrics(dst, dst_default_metrics.metrics, true);
  56         dst->expires = 0UL;
  57 #ifdef CONFIG_XFRM
  58         dst->xfrm = NULL;
  59 #endif
  60         dst->input = dst_discard;
  61         dst->output = dst_discard_out;
  62         dst->error = 0;
  63         dst->obsolete = initial_obsolete;
  64         dst->header_len = 0;
  65         dst->trailer_len = 0;
  66 #ifdef CONFIG_IP_ROUTE_CLASSID
  67         dst->tclassid = 0;
  68 #endif
  69         dst->lwtstate = NULL;
  70         atomic_set(&dst->__refcnt, initial_ref);
  71         dst->__use = 0;
  72         dst->lastuse = jiffies;
  73         dst->flags = flags;
  74         if (!(flags & DST_NOCOUNT))
  75                 dst_entries_add(ops, 1);
  76 }
  77 EXPORT_SYMBOL(dst_init);
  78 
  79 void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
  80                 int initial_ref, int initial_obsolete, unsigned short flags)
  81 {
  82         struct dst_entry *dst;
  83 
  84         if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) {
  85                 if (ops->gc(ops)) {
  86                         printk_ratelimited(KERN_NOTICE "Route cache is full: "
  87                                            "consider increasing sysctl "
  88                                            "net.ipv[4|6].route.max_size.\n");
  89                         return NULL;
  90                 }
  91         }
  92 
  93         dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
  94         if (!dst)
  95                 return NULL;
  96 
  97         dst_init(dst, ops, dev, initial_ref, initial_obsolete, flags);
  98 
  99         return dst;
 100 }
 101 EXPORT_SYMBOL(dst_alloc);
 102 
 103 struct dst_entry *dst_destroy(struct dst_entry * dst)
 104 {
 105         struct dst_entry *child = NULL;
 106 
 107         smp_rmb();
 108 
 109 #ifdef CONFIG_XFRM
 110         if (dst->xfrm) {
 111                 struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
 112 
 113                 child = xdst->child;
 114         }
 115 #endif
 116         if (!(dst->flags & DST_NOCOUNT))
 117                 dst_entries_add(dst->ops, -1);
 118 
 119         if (dst->ops->destroy)
 120                 dst->ops->destroy(dst);
 121         if (dst->dev)
 122                 dev_put(dst->dev);
 123 
 124         lwtstate_put(dst->lwtstate);
 125 
 126         if (dst->flags & DST_METADATA)
 127                 metadata_dst_free((struct metadata_dst *)dst);
 128         else
 129                 kmem_cache_free(dst->ops->kmem_cachep, dst);
 130 
 131         dst = child;
 132         if (dst)
 133                 dst_release_immediate(dst);
 134         return NULL;
 135 }
 136 EXPORT_SYMBOL(dst_destroy);
 137 
 138 static void dst_destroy_rcu(struct rcu_head *head)
 139 {
 140         struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head);
 141 
 142         dst = dst_destroy(dst);
 143 }
 144 
 145 /* Operations to mark dst as DEAD and clean up the net device referenced
 146  * by dst:
 147  * 1. put the dst under loopback interface and discard all tx/rx packets
 148  *    on this route.
 149  * 2. release the net_device
 150  * This function should be called when removing routes from the fib tree
 151  * in preparation for a NETDEV_DOWN/NETDEV_UNREGISTER event and also to
 152  * make the next dst_ops->check() fail.
 153  */
 154 void dst_dev_put(struct dst_entry *dst)
 155 {
 156         struct net_device *dev = dst->dev;
 157 
 158         dst->obsolete = DST_OBSOLETE_DEAD;
 159         if (dst->ops->ifdown)
 160                 dst->ops->ifdown(dst, dev, true);
 161         dst->input = dst_discard;
 162         dst->output = dst_discard_out;
 163         dst->dev = blackhole_netdev;
 164         dev_hold(dst->dev);
 165         dev_put(dev);
 166 }
 167 EXPORT_SYMBOL(dst_dev_put);
 168 
 169 void dst_release(struct dst_entry *dst)
 170 {
 171         if (dst) {
 172                 int newrefcnt;
 173 
 174                 newrefcnt = atomic_dec_return(&dst->__refcnt);
 175                 if (WARN_ONCE(newrefcnt < 0, "dst_release underflow"))
 176                         net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
 177                                              __func__, dst, newrefcnt);
 178                 if (!newrefcnt)
 179                         call_rcu(&dst->rcu_head, dst_destroy_rcu);
 180         }
 181 }
 182 EXPORT_SYMBOL(dst_release);
 183 
 184 void dst_release_immediate(struct dst_entry *dst)
 185 {
 186         if (dst) {
 187                 int newrefcnt;
 188 
 189                 newrefcnt = atomic_dec_return(&dst->__refcnt);
 190                 if (WARN_ONCE(newrefcnt < 0, "dst_release_immediate underflow"))
 191                         net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
 192                                              __func__, dst, newrefcnt);
 193                 if (!newrefcnt)
 194                         dst_destroy(dst);
 195         }
 196 }
 197 EXPORT_SYMBOL(dst_release_immediate);
 198 
 199 u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
 200 {
 201         struct dst_metrics *p = kmalloc(sizeof(*p), GFP_ATOMIC);
 202 
 203         if (p) {
 204                 struct dst_metrics *old_p = (struct dst_metrics *)__DST_METRICS_PTR(old);
 205                 unsigned long prev, new;
 206 
 207                 refcount_set(&p->refcnt, 1);
 208                 memcpy(p->metrics, old_p->metrics, sizeof(p->metrics));
 209 
 210                 new = (unsigned long) p;
 211                 prev = cmpxchg(&dst->_metrics, old, new);
 212 
 213                 if (prev != old) {
 214                         kfree(p);
 215                         p = (struct dst_metrics *)__DST_METRICS_PTR(prev);
 216                         if (prev & DST_METRICS_READ_ONLY)
 217                                 p = NULL;
 218                 } else if (prev & DST_METRICS_REFCOUNTED) {
 219                         if (refcount_dec_and_test(&old_p->refcnt))
 220                                 kfree(old_p);
 221                 }
 222         }
 223         BUILD_BUG_ON(offsetof(struct dst_metrics, metrics) != 0);
 224         return (u32 *)p;
 225 }
 226 EXPORT_SYMBOL(dst_cow_metrics_generic);
 227 
 228 /* Caller asserts that dst_metrics_read_only(dst) is false.  */
 229 void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
 230 {
 231         unsigned long prev, new;
 232 
 233         new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
 234         prev = cmpxchg(&dst->_metrics, old, new);
 235         if (prev == old)
 236                 kfree(__DST_METRICS_PTR(old));
 237 }
 238 EXPORT_SYMBOL(__dst_destroy_metrics_generic);
 239 
 240 static struct dst_ops md_dst_ops = {
 241         .family =               AF_UNSPEC,
 242 };
 243 
 244 static int dst_md_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 245 {
 246         WARN_ONCE(1, "Attempting to call output on metadata dst\n");
 247         kfree_skb(skb);
 248         return 0;
 249 }
 250 
 251 static int dst_md_discard(struct sk_buff *skb)
 252 {
 253         WARN_ONCE(1, "Attempting to call input on metadata dst\n");
 254         kfree_skb(skb);
 255         return 0;
 256 }
 257 
 258 static void __metadata_dst_init(struct metadata_dst *md_dst,
 259                                 enum metadata_type type, u8 optslen)
 260 
 261 {
 262         struct dst_entry *dst;
 263 
 264         dst = &md_dst->dst;
 265         dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE,
 266                  DST_METADATA | DST_NOCOUNT);
 267 
 268         dst->input = dst_md_discard;
 269         dst->output = dst_md_discard_out;
 270 
 271         memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst));
 272         md_dst->type = type;
 273 }
 274 
 275 struct metadata_dst *metadata_dst_alloc(u8 optslen, enum metadata_type type,
 276                                         gfp_t flags)
 277 {
 278         struct metadata_dst *md_dst;
 279 
 280         md_dst = kmalloc(sizeof(*md_dst) + optslen, flags);
 281         if (!md_dst)
 282                 return NULL;
 283 
 284         __metadata_dst_init(md_dst, type, optslen);
 285 
 286         return md_dst;
 287 }
 288 EXPORT_SYMBOL_GPL(metadata_dst_alloc);
 289 
 290 void metadata_dst_free(struct metadata_dst *md_dst)
 291 {
 292 #ifdef CONFIG_DST_CACHE
 293         if (md_dst->type == METADATA_IP_TUNNEL)
 294                 dst_cache_destroy(&md_dst->u.tun_info.dst_cache);
 295 #endif
 296         kfree(md_dst);
 297 }
 298 EXPORT_SYMBOL_GPL(metadata_dst_free);
 299 
 300 struct metadata_dst __percpu *
 301 metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags)
 302 {
 303         int cpu;
 304         struct metadata_dst __percpu *md_dst;
 305 
 306         md_dst = __alloc_percpu_gfp(sizeof(struct metadata_dst) + optslen,
 307                                     __alignof__(struct metadata_dst), flags);
 308         if (!md_dst)
 309                 return NULL;
 310 
 311         for_each_possible_cpu(cpu)
 312                 __metadata_dst_init(per_cpu_ptr(md_dst, cpu), type, optslen);
 313 
 314         return md_dst;
 315 }
 316 EXPORT_SYMBOL_GPL(metadata_dst_alloc_percpu);
 317 
 318 void metadata_dst_free_percpu(struct metadata_dst __percpu *md_dst)
 319 {
 320 #ifdef CONFIG_DST_CACHE
 321         int cpu;
 322 
 323         for_each_possible_cpu(cpu) {
 324                 struct metadata_dst *one_md_dst = per_cpu_ptr(md_dst, cpu);
 325 
 326                 if (one_md_dst->type == METADATA_IP_TUNNEL)
 327                         dst_cache_destroy(&one_md_dst->u.tun_info.dst_cache);
 328         }
 329 #endif
 330         free_percpu(md_dst);
 331 }
 332 EXPORT_SYMBOL_GPL(metadata_dst_free_percpu);

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