Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/net/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 183 kB image not shown  

Quelle  skbuff.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Routines having to do with the 'struct sk_buff' memory handlers.
 *
 * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>
 * Florian La Roche <rzsfl@rz.uni-sb.de>
 *
 * Fixes:
 * Alan Cox : Fixed the worst of the load
 * balancer bugs.
 * Dave Platt : Interrupt stacking fix.
 * Richard Kooijman : Timestamp fixes.
 * Alan Cox : Changed buffer format.
 * Alan Cox : destructor hook for AF_UNIX etc.
 * Linus Torvalds : Better skb_clone.
 * Alan Cox : Added skb_copy.
 * Alan Cox : Added all the changed routines Linus
 * only put in the headers
 * Ray VanTassle : Fixed --skb->lock in free
 * Alan Cox : skb_copy copy arp field
 * Andi Kleen : slabified it.
 * Robert Olsson : Removed skb_head_pool
 *
 * NOTE:
 * The __skb_ routines should be called with interrupts
 * disabled, or you better be *real* sure that the operation is atomic
 * with respect to whatever list is being frobbed (e.g. via lock_sock()
 * or via disabling bottom half handlers, etc).
 */


/*
 * The functions in this file will not compile correctly with gcc 2.4.x
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/sctp.h>
#include <linux/netdevice.h>
#ifdef CONFIG_NET_CLS_ACT
#include <net/pkt_sched.h>
#endif
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/skbuff_ref.h>
#include <linux/splice.h>
#include <linux/cache.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
#include <linux/errqueue.h>
#include <linux/prefetch.h>
#include <linux/bitfield.h>
#include <linux/if_vlan.h>
#include <linux/mpls.h>
#include <linux/kcov.h>
#include <linux/iov_iter.h>
#include <linux/crc32.h>

#include <net/protocol.h>
#include <net/dst.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <net/gro.h>
#include <net/gso.h>
#include <net/hotdata.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
#include <net/mpls.h>
#include <net/mptcp.h>
#include <net/mctp.h>
#include <net/page_pool/helpers.h>
#include <net/dropreason.h>

#include <linux/uaccess.h>
#include <trace/events/skb.h>
#include <linux/highmem.h>
#include <linux/capability.h>
#include <linux/user_namespace.h>
#include <linux/indirect_call_wrapper.h>
#include <linux/textsearch.h>

#include "dev.h"
#include "devmem.h"
#include "netmem_priv.h"
#include "sock_destructor.h"

#ifdef CONFIG_SKB_EXTENSIONS
static struct kmem_cache *skbuff_ext_cache __ro_after_init;
#endif

#define GRO_MAX_HEAD_PAD (GRO_MAX_HEAD + NET_SKB_PAD + NET_IP_ALIGN)
#define SKB_SMALL_HEAD_SIZE SKB_HEAD_ALIGN(max(MAX_TCP_HEADER, \
            GRO_MAX_HEAD_PAD))

/* We want SKB_SMALL_HEAD_CACHE_SIZE to not be a power of two.
 * This should ensure that SKB_SMALL_HEAD_HEADROOM is a unique
 * size, and we can differentiate heads from skb_small_head_cache
 * vs system slabs by looking at their size (skb_end_offset()).
 */

#define SKB_SMALL_HEAD_CACHE_SIZE     \
 (is_power_of_2(SKB_SMALL_HEAD_SIZE) ?   \
  (SKB_SMALL_HEAD_SIZE + L1_CACHE_BYTES) : \
  SKB_SMALL_HEAD_SIZE)

#define SKB_SMALL_HEAD_HEADROOM      \
 SKB_WITH_OVERHEAD(SKB_SMALL_HEAD_CACHE_SIZE)

/* kcm_write_msgs() relies on casting paged frags to bio_vec to use
 * iov_iter_bvec(). These static asserts ensure the cast is valid is long as the
 * netmem is a page.
 */

static_assert(offsetof(struct bio_vec, bv_page) ==
       offsetof(skb_frag_t, netmem));
static_assert(sizeof_field(struct bio_vec, bv_page) ==
       sizeof_field(skb_frag_t, netmem));

static_assert(offsetof(struct bio_vec, bv_len) == offsetof(skb_frag_t, len));
static_assert(sizeof_field(struct bio_vec, bv_len) ==
       sizeof_field(skb_frag_t, len));

static_assert(offsetof(struct bio_vec, bv_offset) ==
       offsetof(skb_frag_t, offset));
static_assert(sizeof_field(struct bio_vec, bv_offset) ==
       sizeof_field(skb_frag_t, offset));

#undef FN
#define FN(reason) [SKB_DROP_REASON_##reason] = #reason,
static const char * const drop_reasons[] = {
 [SKB_CONSUMED] = "CONSUMED",
 DEFINE_DROP_REASON(FN, FN)
};

static const struct drop_reason_list drop_reasons_core = {
 .reasons = drop_reasons,
 .n_reasons = ARRAY_SIZE(drop_reasons),
};

const struct drop_reason_list __rcu *
drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_NUM] = {
 [SKB_DROP_REASON_SUBSYS_CORE] = RCU_INITIALIZER(&drop_reasons_core),
};
EXPORT_SYMBOL(drop_reasons_by_subsys);

/**
 * drop_reasons_register_subsys - register another drop reason subsystem
 * @subsys: the subsystem to register, must not be the core
 * @list: the list of drop reasons within the subsystem, must point to
 * a statically initialized list
 */

void drop_reasons_register_subsys(enum skb_drop_reason_subsys subsys,
      const struct drop_reason_list *list)
{
 if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
   subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
   "invalid subsystem %d\n", subsys))
  return;

 /* must point to statically allocated memory, so INIT is OK */
 RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], list);
}
EXPORT_SYMBOL_GPL(drop_reasons_register_subsys);

/**
 * drop_reasons_unregister_subsys - unregister a drop reason subsystem
 * @subsys: the subsystem to remove, must not be the core
 *
 * Note: This will synchronize_rcu() to ensure no users when it returns.
 */

void drop_reasons_unregister_subsys(enum skb_drop_reason_subsys subsys)
{
 if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
   subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
   "invalid subsystem %d\n", subsys))
  return;

 RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], NULL);

 synchronize_rcu();
}
EXPORT_SYMBOL_GPL(drop_reasons_unregister_subsys);

/**
 * skb_panic - private function for out-of-line support
 * @skb: buffer
 * @sz: size
 * @addr: address
 * @msg: skb_over_panic or skb_under_panic
 *
 * Out-of-line support for skb_put() and skb_push().
 * Called via the wrapper skb_over_panic() or skb_under_panic().
 * Keep out of line to prevent kernel bloat.
 * __builtin_return_address is not used because it is not always reliable.
 */

static void skb_panic(struct sk_buff *skb, unsigned int sz, void *addr,
        const char msg[])
{
 pr_emerg("%s: text:%px len:%d put:%d head:%px data:%px tail:%#lx end:%#lx dev:%s\n",
   msg, addr, skb->len, sz, skb->head, skb->data,
   (unsigned long)skb->tail, (unsigned long)skb->end,
   skb->dev ? skb->dev->name : "");
 BUG();
}

static void skb_over_panic(struct sk_buff *skb, unsigned int sz, void *addr)
{
 skb_panic(skb, sz, addr, __func__);
}

static void skb_under_panic(struct sk_buff *skb, unsigned int sz, void *addr)
{
 skb_panic(skb, sz, addr, __func__);
}

#define NAPI_SKB_CACHE_SIZE 64
#define NAPI_SKB_CACHE_BULK 16
#define NAPI_SKB_CACHE_HALF (NAPI_SKB_CACHE_SIZE / 2)

struct napi_alloc_cache {
 local_lock_t bh_lock;
 struct page_frag_cache page;
 unsigned int skb_count;
 void *skb_cache[NAPI_SKB_CACHE_SIZE];
};

static DEFINE_PER_CPU(struct page_frag_cache, netdev_alloc_cache);
static DEFINE_PER_CPU(struct napi_alloc_cache, napi_alloc_cache) = {
 .bh_lock = INIT_LOCAL_LOCK(bh_lock),
};

void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask)
{
 struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
 void *data;

 fragsz = SKB_DATA_ALIGN(fragsz);

 local_lock_nested_bh(&napi_alloc_cache.bh_lock);
 data = __page_frag_alloc_align(&nc->page, fragsz,
           GFP_ATOMIC | __GFP_NOWARN, align_mask);
 local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
 return data;

}
EXPORT_SYMBOL(__napi_alloc_frag_align);

void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask)
{
 void *data;

 if (in_hardirq() || irqs_disabled()) {
  struct page_frag_cache *nc = this_cpu_ptr(&netdev_alloc_cache);

  fragsz = SKB_DATA_ALIGN(fragsz);
  data = __page_frag_alloc_align(nc, fragsz,
            GFP_ATOMIC | __GFP_NOWARN,
            align_mask);
 } else {
  local_bh_disable();
  data = __napi_alloc_frag_align(fragsz, align_mask);
  local_bh_enable();
 }
 return data;
}
EXPORT_SYMBOL(__netdev_alloc_frag_align);

static struct sk_buff *napi_skb_cache_get(void)
{
 struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
 struct sk_buff *skb;

 local_lock_nested_bh(&napi_alloc_cache.bh_lock);
 if (unlikely(!nc->skb_count)) {
  nc->skb_count = kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
            GFP_ATOMIC | __GFP_NOWARN,
            NAPI_SKB_CACHE_BULK,
            nc->skb_cache);
  if (unlikely(!nc->skb_count)) {
   local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
   return NULL;
  }
 }

 skb = nc->skb_cache[--nc->skb_count];
 local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
 kasan_mempool_unpoison_object(skb, kmem_cache_size(net_hotdata.skbuff_cache));

 return skb;
}

/**
 * napi_skb_cache_get_bulk - obtain a number of zeroed skb heads from the cache
 * @skbs: pointer to an at least @n-sized array to fill with skb pointers
 * @n: number of entries to provide
 *
 * Tries to obtain @n &sk_buff entries from the NAPI percpu cache and writes
 * the pointers into the provided array @skbs. If there are less entries
 * available, tries to replenish the cache and bulk-allocates the diff from
 * the MM layer if needed.
 * The heads are being zeroed with either memset() or %__GFP_ZERO, so they are
 * ready for {,__}build_skb_around() and don't have any data buffers attached.
 * Must be called *only* from the BH context.
 *
 * Return: number of successfully allocated skbs (@n if no actual allocation
 *    needed or kmem_cache_alloc_bulk() didn't fail).
 */

u32 napi_skb_cache_get_bulk(void **skbs, u32 n)
{
 struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
 u32 bulk, total = n;

 local_lock_nested_bh(&napi_alloc_cache.bh_lock);

 if (nc->skb_count >= n)
  goto get;

 /* No enough cached skbs. Try refilling the cache first */
 bulk = min(NAPI_SKB_CACHE_SIZE - nc->skb_count, NAPI_SKB_CACHE_BULK);
 nc->skb_count += kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
            GFP_ATOMIC | __GFP_NOWARN, bulk,
            &nc->skb_cache[nc->skb_count]);
 if (likely(nc->skb_count >= n))
  goto get;

 /* Still not enough. Bulk-allocate the missing part directly, zeroed */
 n -= kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
       GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN,
       n - nc->skb_count, &skbs[nc->skb_count]);
 if (likely(nc->skb_count >= n))
  goto get;

 /* kmem_cache didn't allocate the number we need, limit the output */
 total -= n - nc->skb_count;
 n = nc->skb_count;

get:
 for (u32 base = nc->skb_count - n, i = 0; i < n; i++) {
  u32 cache_size = kmem_cache_size(net_hotdata.skbuff_cache);

  skbs[i] = nc->skb_cache[base + i];

  kasan_mempool_unpoison_object(skbs[i], cache_size);
  memset(skbs[i], 0, offsetof(struct sk_buff, tail));
 }

 nc->skb_count -= n;
 local_unlock_nested_bh(&napi_alloc_cache.bh_lock);

 return total;
}
EXPORT_SYMBOL_GPL(napi_skb_cache_get_bulk);

static inline void __finalize_skb_around(struct sk_buff *skb, void *data,
      unsigned int size)
{
 struct skb_shared_info *shinfo;

 size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));

 /* Assumes caller memset cleared SKB */
 skb->truesize = SKB_TRUESIZE(size);
 refcount_set(&skb->users, 1);
 skb->head = data;
 skb->data = data;
 skb_reset_tail_pointer(skb);
 skb_set_end_offset(skb, size);
 skb->mac_header = (typeof(skb->mac_header))~0U;
 skb->transport_header = (typeof(skb->transport_header))~0U;
 skb->alloc_cpu = raw_smp_processor_id();
 /* make sure we initialize shinfo sequentially */
 shinfo = skb_shinfo(skb);
 memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
 atomic_set(&shinfo->dataref, 1);

 skb_set_kcov_handle(skb, kcov_common_handle());
}

static inline void *__slab_build_skb(void *data, unsigned int *size)
{
 void *resized;

 /* Must find the allocation size (and grow it to match). */
 *size = ksize(data);
 /* krealloc() will immediately return "data" when
 * "ksize(data)" is requested: it is the existing upper
 * bounds. As a result, GFP_ATOMIC will be ignored. Note
 * that this "new" pointer needs to be passed back to the
 * caller for use so the __alloc_size hinting will be
 * tracked correctly.
 */

 resized = krealloc(data, *size, GFP_ATOMIC);
 WARN_ON_ONCE(resized != data);
 return resized;
}

/* build_skb() variant which can operate on slab buffers.
 * Note that this should be used sparingly as slab buffers
 * cannot be combined efficiently by GRO!
 */

struct sk_buff *slab_build_skb(void *data)
{
 struct sk_buff *skb;
 unsigned int size;

 skb = kmem_cache_alloc(net_hotdata.skbuff_cache,
          GFP_ATOMIC | __GFP_NOWARN);
 if (unlikely(!skb))
  return NULL;

 memset(skb, 0, offsetof(struct sk_buff, tail));
 data = __slab_build_skb(data, &size);
 __finalize_skb_around(skb, data, size);

 return skb;
}
EXPORT_SYMBOL(slab_build_skb);

/* Caller must provide SKB that is memset cleared */
static void __build_skb_around(struct sk_buff *skb, void *data,
          unsigned int frag_size)
{
 unsigned int size = frag_size;

 /* frag_size == 0 is considered deprecated now. Callers
 * using slab buffer should use slab_build_skb() instead.
 */

 if (WARN_ONCE(size == 0, "Use slab_build_skb() instead"))
  data = __slab_build_skb(data, &size);

 __finalize_skb_around(skb, data, size);
}

/**
 * __build_skb - build a network buffer
 * @data: data buffer provided by caller
 * @frag_size: size of data (must not be 0)
 *
 * Allocate a new &sk_buff. Caller provides space holding head and
 * skb_shared_info. @data must have been allocated from the page
 * allocator or vmalloc(). (A @frag_size of 0 to indicate a kmalloc()
 * allocation is deprecated, and callers should use slab_build_skb()
 * instead.)
 * The return is the new skb buffer.
 * On a failure the return is %NULL, and @data is not freed.
 * Notes :
 *  Before IO, driver allocates only data buffer where NIC put incoming frame
 *  Driver should add room at head (NET_SKB_PAD) and
 *  MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
 *  After IO, driver calls build_skb(), to allocate sk_buff and populate it
 *  before giving packet to stack.
 *  RX rings only contains data buffers, not full skbs.
 */

struct sk_buff *__build_skb(void *data, unsigned int frag_size)
{
 struct sk_buff *skb;

 skb = kmem_cache_alloc(net_hotdata.skbuff_cache,
          GFP_ATOMIC | __GFP_NOWARN);
 if (unlikely(!skb))
  return NULL;

 memset(skb, 0, offsetof(struct sk_buff, tail));
 __build_skb_around(skb, data, frag_size);

 return skb;
}

/* build_skb() is wrapper over __build_skb(), that specifically
 * takes care of skb->head and skb->pfmemalloc
 */

struct sk_buff *build_skb(void *data, unsigned int frag_size)
{
 struct sk_buff *skb = __build_skb(data, frag_size);

 if (likely(skb && frag_size)) {
  skb->head_frag = 1;
  skb_propagate_pfmemalloc(virt_to_head_page(data), skb);
 }
 return skb;
}
EXPORT_SYMBOL(build_skb);

/**
 * build_skb_around - build a network buffer around provided skb
 * @skb: sk_buff provide by caller, must be memset cleared
 * @data: data buffer provided by caller
 * @frag_size: size of data
 */

struct sk_buff *build_skb_around(struct sk_buff *skb,
     void *data, unsigned int frag_size)
{
 if (unlikely(!skb))
  return NULL;

 __build_skb_around(skb, data, frag_size);

 if (frag_size) {
  skb->head_frag = 1;
  skb_propagate_pfmemalloc(virt_to_head_page(data), skb);
 }
 return skb;
}
EXPORT_SYMBOL(build_skb_around);

/**
 * __napi_build_skb - build a network buffer
 * @data: data buffer provided by caller
 * @frag_size: size of data
 *
 * Version of __build_skb() that uses NAPI percpu caches to obtain
 * skbuff_head instead of inplace allocation.
 *
 * Returns a new &sk_buff on success, %NULL on allocation failure.
 */

static struct sk_buff *__napi_build_skb(void *data, unsigned int frag_size)
{
 struct sk_buff *skb;

 skb = napi_skb_cache_get();
 if (unlikely(!skb))
  return NULL;

 memset(skb, 0, offsetof(struct sk_buff, tail));
 __build_skb_around(skb, data, frag_size);

 return skb;
}

/**
 * napi_build_skb - build a network buffer
 * @data: data buffer provided by caller
 * @frag_size: size of data
 *
 * Version of __napi_build_skb() that takes care of skb->head_frag
 * and skb->pfmemalloc when the data is a page or page fragment.
 *
 * Returns a new &sk_buff on success, %NULL on allocation failure.
 */

struct sk_buff *napi_build_skb(void *data, unsigned int frag_size)
{
 struct sk_buff *skb = __napi_build_skb(data, frag_size);

 if (likely(skb) && frag_size) {
  skb->head_frag = 1;
  skb_propagate_pfmemalloc(virt_to_head_page(data), skb);
 }

 return skb;
}
EXPORT_SYMBOL(napi_build_skb);

/*
 * kmalloc_reserve is a wrapper around kmalloc_node_track_caller that tells
 * the caller if emergency pfmemalloc reserves are being used. If it is and
 * the socket is later found to be SOCK_MEMALLOC then PFMEMALLOC reserves
 * may be used. Otherwise, the packet data may be discarded until enough
 * memory is free
 */

static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node,
        bool *pfmemalloc)
{
 bool ret_pfmemalloc = false;
 size_t obj_size;
 void *obj;

 obj_size = SKB_HEAD_ALIGN(*size);
 if (obj_size <= SKB_SMALL_HEAD_CACHE_SIZE &&
     !(flags & KMALLOC_NOT_NORMAL_BITS)) {
  obj = kmem_cache_alloc_node(net_hotdata.skb_small_head_cache,
    flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
    node);
  *size = SKB_SMALL_HEAD_CACHE_SIZE;
  if (obj || !(gfp_pfmemalloc_allowed(flags)))
   goto out;
  /* Try again but now we are using pfmemalloc reserves */
  ret_pfmemalloc = true;
  obj = kmem_cache_alloc_node(net_hotdata.skb_small_head_cache, flags, node);
  goto out;
 }

 obj_size = kmalloc_size_roundup(obj_size);
 /* The following cast might truncate high-order bits of obj_size, this
 * is harmless because kmalloc(obj_size >= 2^32) will fail anyway.
 */

 *size = (unsigned int)obj_size;

 /*
 * Try a regular allocation, when that fails and we're not entitled
 * to the reserves, fail.
 */

 obj = kmalloc_node_track_caller(obj_size,
     flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
     node);
 if (obj || !(gfp_pfmemalloc_allowed(flags)))
  goto out;

 /* Try again but now we are using pfmemalloc reserves */
 ret_pfmemalloc = true;
 obj = kmalloc_node_track_caller(obj_size, flags, node);

out:
 if (pfmemalloc)
  *pfmemalloc = ret_pfmemalloc;

 return obj;
}

/*  Allocate a new skbuff. We do this ourselves so we can fill in a few
 * 'private' fields and also do memory statistics to find all the
 * [BEEP] leaks.
 *
 */


/**
 * __alloc_skb - allocate a network buffer
 * @size: size to allocate
 * @gfp_mask: allocation mask
 * @flags: If SKB_ALLOC_FCLONE is set, allocate from fclone cache
 * instead of head cache and allocate a cloned (child) skb.
 * If SKB_ALLOC_RX is set, __GFP_MEMALLOC will be used for
 * allocations in case the data is required for writeback
 * @node: numa node to allocate memory on
 *
 * Allocate a new &sk_buff. The returned buffer has no headroom and a
 * tail room of at least size bytes. The object has a reference count
 * of one. The return is the buffer. On a failure the return is %NULL.
 *
 * Buffers may only be allocated from interrupts using a @gfp_mask of
 * %GFP_ATOMIC.
 */

struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
       int flags, int node)
{
 struct kmem_cache *cache;
 struct sk_buff *skb;
 bool pfmemalloc;
 u8 *data;

 cache = (flags & SKB_ALLOC_FCLONE)
  ? net_hotdata.skbuff_fclone_cache : net_hotdata.skbuff_cache;

 if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
  gfp_mask |= __GFP_MEMALLOC;

 /* Get the HEAD */
 if ((flags & (SKB_ALLOC_FCLONE | SKB_ALLOC_NAPI)) == SKB_ALLOC_NAPI &&
     likely(node == NUMA_NO_NODE || node == numa_mem_id()))
  skb = napi_skb_cache_get();
 else
  skb = kmem_cache_alloc_node(cache, gfp_mask & ~GFP_DMA, node);
 if (unlikely(!skb))
  return NULL;
 prefetchw(skb);

 /* We do our best to align skb_shared_info on a separate cache
 * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
 * aligned memory blocks, unless SLUB/SLAB debug is enabled.
 * Both skb->head and skb_shared_info are cache line aligned.
 */

 data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc);
 if (unlikely(!data))
  goto nodata;
 /* kmalloc_size_roundup() might give us more room than requested.
 * Put skb_shared_info exactly at the end of allocated zone,
 * to allow max possible filling before reallocation.
 */

 prefetchw(data + SKB_WITH_OVERHEAD(size));

 /*
 * Only clear those fields we need to clear, not those that we will
 * actually initialise below. Hence, don't put any more fields after
 * the tail pointer in struct sk_buff!
 */

 memset(skb, 0, offsetof(struct sk_buff, tail));
 __build_skb_around(skb, data, size);
 skb->pfmemalloc = pfmemalloc;

 if (flags & SKB_ALLOC_FCLONE) {
  struct sk_buff_fclones *fclones;

  fclones = container_of(skb, struct sk_buff_fclones, skb1);

  skb->fclone = SKB_FCLONE_ORIG;
  refcount_set(&fclones->fclone_ref, 1);
 }

 return skb;

nodata:
 kmem_cache_free(cache, skb);
 return NULL;
}
EXPORT_SYMBOL(__alloc_skb);

/**
 * __netdev_alloc_skb - allocate an skbuff for rx on a specific device
 * @dev: network device to receive on
 * @len: length to allocate
 * @gfp_mask: get_free_pages mask, passed to alloc_skb
 *
 * Allocate a new &sk_buff and assign it a usage count of one. The
 * buffer has NET_SKB_PAD headroom built in. Users should allocate
 * the headroom they think they need without accounting for the
 * built in space. The built in space is used for optimisations.
 *
 * %NULL is returned if there is no free memory.
 */

struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
       gfp_t gfp_mask)
{
 struct page_frag_cache *nc;
 struct sk_buff *skb;
 bool pfmemalloc;
 void *data;

 len += NET_SKB_PAD;

 /* If requested length is either too small or too big,
 * we use kmalloc() for skb->head allocation.
 */

 if (len <= SKB_WITH_OVERHEAD(SKB_SMALL_HEAD_CACHE_SIZE) ||
     len > SKB_WITH_OVERHEAD(PAGE_SIZE) ||
     (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
  skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
  if (!skb)
   goto skb_fail;
  goto skb_success;
 }

 len = SKB_HEAD_ALIGN(len);

 if (sk_memalloc_socks())
  gfp_mask |= __GFP_MEMALLOC;

 if (in_hardirq() || irqs_disabled()) {
  nc = this_cpu_ptr(&netdev_alloc_cache);
  data = page_frag_alloc(nc, len, gfp_mask);
  pfmemalloc = page_frag_cache_is_pfmemalloc(nc);
 } else {
  local_bh_disable();
  local_lock_nested_bh(&napi_alloc_cache.bh_lock);

  nc = this_cpu_ptr(&napi_alloc_cache.page);
  data = page_frag_alloc(nc, len, gfp_mask);
  pfmemalloc = page_frag_cache_is_pfmemalloc(nc);

  local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
  local_bh_enable();
 }

 if (unlikely(!data))
  return NULL;

 skb = __build_skb(data, len);
 if (unlikely(!skb)) {
  skb_free_frag(data);
  return NULL;
 }

 if (pfmemalloc)
  skb->pfmemalloc = 1;
 skb->head_frag = 1;

skb_success:
 skb_reserve(skb, NET_SKB_PAD);
 skb->dev = dev;

skb_fail:
 return skb;
}
EXPORT_SYMBOL(__netdev_alloc_skb);

/**
 * napi_alloc_skb - allocate skbuff for rx in a specific NAPI instance
 * @napi: napi instance this buffer was allocated for
 * @len: length to allocate
 *
 * Allocate a new sk_buff for use in NAPI receive.  This buffer will
 * attempt to allocate the head from a special reserved region used
 * only for NAPI Rx allocation.  By doing this we can save several
 * CPU cycles by avoiding having to disable and re-enable IRQs.
 *
 * %NULL is returned if there is no free memory.
 */

struct sk_buff *napi_alloc_skb(struct napi_struct *napi, unsigned int len)
{
 gfp_t gfp_mask = GFP_ATOMIC | __GFP_NOWARN;
 struct napi_alloc_cache *nc;
 struct sk_buff *skb;
 bool pfmemalloc;
 void *data;

 DEBUG_NET_WARN_ON_ONCE(!in_softirq());
 len += NET_SKB_PAD + NET_IP_ALIGN;

 /* If requested length is either too small or too big,
 * we use kmalloc() for skb->head allocation.
 */

 if (len <= SKB_WITH_OVERHEAD(SKB_SMALL_HEAD_CACHE_SIZE) ||
     len > SKB_WITH_OVERHEAD(PAGE_SIZE) ||
     (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
  skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX | SKB_ALLOC_NAPI,
      NUMA_NO_NODE);
  if (!skb)
   goto skb_fail;
  goto skb_success;
 }

 len = SKB_HEAD_ALIGN(len);

 if (sk_memalloc_socks())
  gfp_mask |= __GFP_MEMALLOC;

 local_lock_nested_bh(&napi_alloc_cache.bh_lock);
 nc = this_cpu_ptr(&napi_alloc_cache);

 data = page_frag_alloc(&nc->page, len, gfp_mask);
 pfmemalloc = page_frag_cache_is_pfmemalloc(&nc->page);
 local_unlock_nested_bh(&napi_alloc_cache.bh_lock);

 if (unlikely(!data))
  return NULL;

 skb = __napi_build_skb(data, len);
 if (unlikely(!skb)) {
  skb_free_frag(data);
  return NULL;
 }

 if (pfmemalloc)
  skb->pfmemalloc = 1;
 skb->head_frag = 1;

skb_success:
 skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
 skb->dev = napi->dev;

skb_fail:
 return skb;
}
EXPORT_SYMBOL(napi_alloc_skb);

void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem,
       int off, int size, unsigned int truesize)
{
 DEBUG_NET_WARN_ON_ONCE(size > truesize);

 skb_fill_netmem_desc(skb, i, netmem, off, size);
 skb->len += size;
 skb->data_len += size;
 skb->truesize += truesize;
}
EXPORT_SYMBOL(skb_add_rx_frag_netmem);

void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size,
     unsigned int truesize)
{
 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];

 DEBUG_NET_WARN_ON_ONCE(size > truesize);

 skb_frag_size_add(frag, size);
 skb->len += size;
 skb->data_len += size;
 skb->truesize += truesize;
}
EXPORT_SYMBOL(skb_coalesce_rx_frag);

static void skb_drop_list(struct sk_buff **listp)
{
 kfree_skb_list(*listp);
 *listp = NULL;
}

static inline void skb_drop_fraglist(struct sk_buff *skb)
{
 skb_drop_list(&skb_shinfo(skb)->frag_list);
}

static void skb_clone_fraglist(struct sk_buff *skb)
{
 struct sk_buff *list;

 skb_walk_frags(skb, list)
  skb_get(list);
}

int skb_pp_cow_data(struct page_pool *pool, struct sk_buff **pskb,
      unsigned int headroom)
{
#if IS_ENABLED(CONFIG_PAGE_POOL)
 u32 size, truesize, len, max_head_size, off;
 struct sk_buff *skb = *pskb, *nskb;
 int err, i, head_off;
 void *data;

 /* XDP does not support fraglist so we need to linearize
 * the skb.
 */

 if (skb_has_frag_list(skb))
  return -EOPNOTSUPP;

 max_head_size = SKB_WITH_OVERHEAD(PAGE_SIZE - headroom);
 if (skb->len > max_head_size + MAX_SKB_FRAGS * PAGE_SIZE)
  return -ENOMEM;

 size = min_t(u32, skb->len, max_head_size);
 truesize = SKB_HEAD_ALIGN(size) + headroom;
 data = page_pool_dev_alloc_va(pool, &truesize);
 if (!data)
  return -ENOMEM;

 nskb = napi_build_skb(data, truesize);
 if (!nskb) {
  page_pool_free_va(pool, data, true);
  return -ENOMEM;
 }

 skb_reserve(nskb, headroom);
 skb_copy_header(nskb, skb);
 skb_mark_for_recycle(nskb);

 err = skb_copy_bits(skb, 0, nskb->data, size);
 if (err) {
  consume_skb(nskb);
  return err;
 }
 skb_put(nskb, size);

 head_off = skb_headroom(nskb) - skb_headroom(skb);
 skb_headers_offset_update(nskb, head_off);

 off = size;
 len = skb->len - off;
 for (i = 0; i < MAX_SKB_FRAGS && off < skb->len; i++) {
  struct page *page;
  u32 page_off;

  size = min_t(u32, len, PAGE_SIZE);
  truesize = size;

  page = page_pool_dev_alloc(pool, &page_off, &truesize);
  if (!page) {
   consume_skb(nskb);
   return -ENOMEM;
  }

  skb_add_rx_frag(nskb, i, page, page_off, size, truesize);
  err = skb_copy_bits(skb, off, page_address(page) + page_off,
        size);
  if (err) {
   consume_skb(nskb);
   return err;
  }

  len -= size;
  off += size;
 }

 consume_skb(skb);
 *pskb = nskb;

 return 0;
#else
 return -EOPNOTSUPP;
#endif
}
EXPORT_SYMBOL(skb_pp_cow_data);

int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb,
    const struct bpf_prog *prog)
{
 if (!prog->aux->xdp_has_frags)
  return -EINVAL;

 return skb_pp_cow_data(pool, pskb, XDP_PACKET_HEADROOM);
}
EXPORT_SYMBOL(skb_cow_data_for_xdp);

#if IS_ENABLED(CONFIG_PAGE_POOL)
bool napi_pp_put_page(netmem_ref netmem)
{
 netmem = netmem_compound_head(netmem);

 if (unlikely(!netmem_is_pp(netmem)))
  return false;

 page_pool_put_full_netmem(netmem_get_pp(netmem), netmem, false);

 return true;
}
EXPORT_SYMBOL(napi_pp_put_page);
#endif

static bool skb_pp_recycle(struct sk_buff *skb, void *data)
{
 if (!IS_ENABLED(CONFIG_PAGE_POOL) || !skb->pp_recycle)
  return false;
 return napi_pp_put_page(page_to_netmem(virt_to_page(data)));
}

/**
 * skb_pp_frag_ref() - Increase fragment references of a page pool aware skb
 * @skb: page pool aware skb
 *
 * Increase the fragment reference count (pp_ref_count) of a skb. This is
 * intended to gain fragment references only for page pool aware skbs,
 * i.e. when skb->pp_recycle is true, and not for fragments in a
 * non-pp-recycling skb. It has a fallback to increase references on normal
 * pages, as page pool aware skbs may also have normal page fragments.
 */

static int skb_pp_frag_ref(struct sk_buff *skb)
{
 struct skb_shared_info *shinfo;
 netmem_ref head_netmem;
 int i;

 if (!skb->pp_recycle)
  return -EINVAL;

 shinfo = skb_shinfo(skb);

 for (i = 0; i < shinfo->nr_frags; i++) {
  head_netmem = netmem_compound_head(shinfo->frags[i].netmem);
  if (likely(netmem_is_pp(head_netmem)))
   page_pool_ref_netmem(head_netmem);
  else
   page_ref_inc(netmem_to_page(head_netmem));
 }
 return 0;
}

static void skb_kfree_head(void *head, unsigned int end_offset)
{
 if (end_offset == SKB_SMALL_HEAD_HEADROOM)
  kmem_cache_free(net_hotdata.skb_small_head_cache, head);
 else
  kfree(head);
}

static void skb_free_head(struct sk_buff *skb)
{
 unsigned char *head = skb->head;

 if (skb->head_frag) {
  if (skb_pp_recycle(skb, head))
   return;
  skb_free_frag(head);
 } else {
  skb_kfree_head(head, skb_end_offset(skb));
 }
}

static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason)
{
 struct skb_shared_info *shinfo = skb_shinfo(skb);
 int i;

 if (!skb_data_unref(skb, shinfo))
  goto exit;

 if (skb_zcopy(skb)) {
  bool skip_unref = shinfo->flags & SKBFL_MANAGED_FRAG_REFS;

  skb_zcopy_clear(skb, true);
  if (skip_unref)
   goto free_head;
 }

 for (i = 0; i < shinfo->nr_frags; i++)
  __skb_frag_unref(&shinfo->frags[i], skb->pp_recycle);

free_head:
 if (shinfo->frag_list)
  kfree_skb_list_reason(shinfo->frag_list, reason);

 skb_free_head(skb);
exit:
 /* When we clone an SKB we copy the reycling bit. The pp_recycle
 * bit is only set on the head though, so in order to avoid races
 * while trying to recycle fragments on __skb_frag_unref() we need
 * to make one SKB responsible for triggering the recycle path.
 * So disable the recycling bit if an SKB is cloned and we have
 * additional references to the fragmented part of the SKB.
 * Eventually the last SKB will have the recycling bit set and it's
 * dataref set to 0, which will trigger the recycling
 */

 skb->pp_recycle = 0;
}

/*
 * Free an skbuff by memory without cleaning the state.
 */

static void kfree_skbmem(struct sk_buff *skb)
{
 struct sk_buff_fclones *fclones;

 switch (skb->fclone) {
 case SKB_FCLONE_UNAVAILABLE:
  kmem_cache_free(net_hotdata.skbuff_cache, skb);
  return;

 case SKB_FCLONE_ORIG:
  fclones = container_of(skb, struct sk_buff_fclones, skb1);

  /* We usually free the clone (TX completion) before original skb
 * This test would have no chance to be true for the clone,
 * while here, branch prediction will be good.
 */

  if (refcount_read(&fclones->fclone_ref) == 1)
   goto fastpath;
  break;

 default/* SKB_FCLONE_CLONE */
  fclones = container_of(skb, struct sk_buff_fclones, skb2);
  break;
 }
 if (!refcount_dec_and_test(&fclones->fclone_ref))
  return;
fastpath:
 kmem_cache_free(net_hotdata.skbuff_fclone_cache, fclones);
}

void skb_release_head_state(struct sk_buff *skb)
{
 skb_dst_drop(skb);
 if (skb->destructor) {
  DEBUG_NET_WARN_ON_ONCE(in_hardirq());
  skb->destructor(skb);
 }
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
 nf_conntrack_put(skb_nfct(skb));
#endif
 skb_ext_put(skb);
}

/* Free everything but the sk_buff shell. */
static void skb_release_all(struct sk_buff *skb, enum skb_drop_reason reason)
{
 skb_release_head_state(skb);
 if (likely(skb->head))
  skb_release_data(skb, reason);
}

/**
 * __kfree_skb - private function
 * @skb: buffer
 *
 * Free an sk_buff. Release anything attached to the buffer.
 * Clean the state. This is an internal helper function. Users should
 * always call kfree_skb
 */


void __kfree_skb(struct sk_buff *skb)
{
 skb_release_all(skb, SKB_DROP_REASON_NOT_SPECIFIED);
 kfree_skbmem(skb);
}
EXPORT_SYMBOL(__kfree_skb);

static __always_inline
bool __sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb,
     enum skb_drop_reason reason)
{
 if (unlikely(!skb_unref(skb)))
  return false;

 DEBUG_NET_WARN_ON_ONCE(reason == SKB_NOT_DROPPED_YET ||
          u32_get_bits(reason,
         SKB_DROP_REASON_SUBSYS_MASK) >=
    SKB_DROP_REASON_SUBSYS_NUM);

 if (reason == SKB_CONSUMED)
  trace_consume_skb(skb, __builtin_return_address(0));
 else
  trace_kfree_skb(skb, __builtin_return_address(0), reason, sk);
 return true;
}

/**
 * sk_skb_reason_drop - free an sk_buff with special reason
 * @sk: the socket to receive @skb, or NULL if not applicable
 * @skb: buffer to free
 * @reason: reason why this skb is dropped
 *
 * Drop a reference to the buffer and free it if the usage count has hit
 * zero. Meanwhile, pass the receiving socket and drop reason to
 * 'kfree_skb' tracepoint.
 */

void __fix_address
sk_skb_reason_drop(struct sock *sk, struct sk_buff *skb, enum skb_drop_reason reason)
{
 if (__sk_skb_reason_drop(sk, skb, reason))
  __kfree_skb(skb);
}
EXPORT_SYMBOL(sk_skb_reason_drop);

#define KFREE_SKB_BULK_SIZE 16

struct skb_free_array {
 unsigned int skb_count;
 void *skb_array[KFREE_SKB_BULK_SIZE];
};

static void kfree_skb_add_bulk(struct sk_buff *skb,
          struct skb_free_array *sa,
          enum skb_drop_reason reason)
{
 /* if SKB is a clone, don't handle this case */
 if (unlikely(skb->fclone != SKB_FCLONE_UNAVAILABLE)) {
  __kfree_skb(skb);
  return;
 }

 skb_release_all(skb, reason);
 sa->skb_array[sa->skb_count++] = skb;

 if (unlikely(sa->skb_count == KFREE_SKB_BULK_SIZE)) {
  kmem_cache_free_bulk(net_hotdata.skbuff_cache, KFREE_SKB_BULK_SIZE,
         sa->skb_array);
  sa->skb_count = 0;
 }
}

void __fix_address
kfree_skb_list_reason(struct sk_buff *segs, enum skb_drop_reason reason)
{
 struct skb_free_array sa;

 sa.skb_count = 0;

 while (segs) {
  struct sk_buff *next = segs->next;

  if (__sk_skb_reason_drop(NULL, segs, reason)) {
   skb_poison_list(segs);
   kfree_skb_add_bulk(segs, &sa, reason);
  }

  segs = next;
 }

 if (sa.skb_count)
  kmem_cache_free_bulk(net_hotdata.skbuff_cache, sa.skb_count, sa.skb_array);
}
EXPORT_SYMBOL(kfree_skb_list_reason);

/* Dump skb information and contents.
 *
 * Must only be called from net_ratelimit()-ed paths.
 *
 * Dumps whole packets if full_pkt, only headers otherwise.
 */

void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt)
{
 struct skb_shared_info *sh = skb_shinfo(skb);
 struct net_device *dev = skb->dev;
 struct sock *sk = skb->sk;
 struct sk_buff *list_skb;
 bool has_mac, has_trans;
 int headroom, tailroom;
 int i, len, seg_len;

 if (full_pkt)
  len = skb->len;
 else
  len = min_t(int, skb->len, MAX_HEADER + 128);

 headroom = skb_headroom(skb);
 tailroom = skb_tailroom(skb);

 has_mac = skb_mac_header_was_set(skb);
 has_trans = skb_transport_header_was_set(skb);

 printk("%sskb len=%u headroom=%u headlen=%u tailroom=%u\n"
        "mac=(%d,%d) mac_len=%u net=(%d,%d) trans=%d\n"
        "shinfo(txflags=%u nr_frags=%u gso(size=%hu type=%u segs=%hu))\n"
        "csum(0x%x start=%u offset=%u ip_summed=%u complete_sw=%u valid=%u level=%u)\n"
        "hash(0x%x sw=%u l4=%u) proto=0x%04x pkttype=%u iif=%d\n"
        "priority=0x%x mark=0x%x alloc_cpu=%u vlan_all=0x%x\n"
        "encapsulation=%d inner(proto=0x%04x, mac=%u, net=%u, trans=%u)\n",
        level, skb->len, headroom, skb_headlen(skb), tailroom,
        has_mac ? skb->mac_header : -1,
        has_mac ? skb_mac_header_len(skb) : -1,
        skb->mac_len,
        skb->network_header,
        has_trans ? skb_network_header_len(skb) : -1,
        has_trans ? skb->transport_header : -1,
        sh->tx_flags, sh->nr_frags,
        sh->gso_size, sh->gso_type, sh->gso_segs,
        skb->csum, skb->csum_start, skb->csum_offset, skb->ip_summed,
        skb->csum_complete_sw, skb->csum_valid, skb->csum_level,
        skb->hash, skb->sw_hash, skb->l4_hash,
        ntohs(skb->protocol), skb->pkt_type, skb->skb_iif,
        skb->priority, skb->mark, skb->alloc_cpu, skb->vlan_all,
        skb->encapsulation, skb->inner_protocol, skb->inner_mac_header,
        skb->inner_network_header, skb->inner_transport_header);

 if (dev)
  printk("%sdev name=%s feat=%pNF\n",
         level, dev->name, &dev->features);
 if (sk)
  printk("%ssk family=%hu type=%u proto=%u\n",
         level, sk->sk_family, sk->sk_type, sk->sk_protocol);

 if (full_pkt && headroom)
  print_hex_dump(level, "skb headroom: ", DUMP_PREFIX_OFFSET,
          16, 1, skb->head, headroom, false);

 seg_len = min_t(int, skb_headlen(skb), len);
 if (seg_len)
  print_hex_dump(level, "skb linear: ", DUMP_PREFIX_OFFSET,
          16, 1, skb->data, seg_len, false);
 len -= seg_len;

 if (full_pkt && tailroom)
  print_hex_dump(level, "skb tailroom: ", DUMP_PREFIX_OFFSET,
          16, 1, skb_tail_pointer(skb), tailroom, false);

 for (i = 0; len && i < skb_shinfo(skb)->nr_frags; i++) {
  skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
  u32 p_off, p_len, copied;
  struct page *p;
  u8 *vaddr;

  if (skb_frag_is_net_iov(frag)) {
   printk("%sskb frag %d: not readable\n", level, i);
   len -= skb_frag_size(frag);
   if (!len)
    break;
   continue;
  }

  skb_frag_foreach_page(frag, skb_frag_off(frag),
          skb_frag_size(frag), p, p_off, p_len,
          copied) {
   seg_len = min_t(int, p_len, len);
   vaddr = kmap_atomic(p);
   print_hex_dump(level, "skb frag: ",
           DUMP_PREFIX_OFFSET,
           16, 1, vaddr + p_off, seg_len, false);
   kunmap_atomic(vaddr);
   len -= seg_len;
   if (!len)
    break;
  }
 }

 if (full_pkt && skb_has_frag_list(skb)) {
  printk("skb fraglist:\n");
  skb_walk_frags(skb, list_skb)
   skb_dump(level, list_skb, true);
 }
}
EXPORT_SYMBOL(skb_dump);

/**
 * skb_tx_error - report an sk_buff xmit error
 * @skb: buffer that triggered an error
 *
 * Report xmit error if a device callback is tracking this skb.
 * skb must be freed afterwards.
 */

void skb_tx_error(struct sk_buff *skb)
{
 if (skb) {
  skb_zcopy_downgrade_managed(skb);
  skb_zcopy_clear(skb, true);
 }
}
EXPORT_SYMBOL(skb_tx_error);

#ifdef CONFIG_TRACEPOINTS
/**
 * consume_skb - free an skbuff
 * @skb: buffer to free
 *
 * Drop a ref to the buffer and free it if the usage count has hit zero
 * Functions identically to kfree_skb, but kfree_skb assumes that the frame
 * is being dropped after a failure and notes that
 */

void consume_skb(struct sk_buff *skb)
{
 if (!skb_unref(skb))
  return;

 trace_consume_skb(skb, __builtin_return_address(0));
 __kfree_skb(skb);
}
EXPORT_SYMBOL(consume_skb);
#endif

/**
 * __consume_stateless_skb - free an skbuff, assuming it is stateless
 * @skb: buffer to free
 *
 * Alike consume_skb(), but this variant assumes that this is the last
 * skb reference and all the head states have been already dropped
 */

void __consume_stateless_skb(struct sk_buff *skb)
{
 trace_consume_skb(skb, __builtin_return_address(0));
 skb_release_data(skb, SKB_CONSUMED);
 kfree_skbmem(skb);
}

static void napi_skb_cache_put(struct sk_buff *skb)
{
 struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
 u32 i;

 if (!kasan_mempool_poison_object(skb))
  return;

 local_lock_nested_bh(&napi_alloc_cache.bh_lock);
 nc->skb_cache[nc->skb_count++] = skb;

 if (unlikely(nc->skb_count == NAPI_SKB_CACHE_SIZE)) {
  for (i = NAPI_SKB_CACHE_HALF; i < NAPI_SKB_CACHE_SIZE; i++)
   kasan_mempool_unpoison_object(nc->skb_cache[i],
      kmem_cache_size(net_hotdata.skbuff_cache));

  kmem_cache_free_bulk(net_hotdata.skbuff_cache, NAPI_SKB_CACHE_HALF,
         nc->skb_cache + NAPI_SKB_CACHE_HALF);
  nc->skb_count = NAPI_SKB_CACHE_HALF;
 }
 local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
}

void __napi_kfree_skb(struct sk_buff *skb, enum skb_drop_reason reason)
{
 skb_release_all(skb, reason);
 napi_skb_cache_put(skb);
}

void napi_skb_free_stolen_head(struct sk_buff *skb)
{
 if (unlikely(skb->slow_gro)) {
  nf_reset_ct(skb);
  skb_dst_drop(skb);
  skb_ext_put(skb);
  skb_orphan(skb);
  skb->slow_gro = 0;
 }
 napi_skb_cache_put(skb);
}

void napi_consume_skb(struct sk_buff *skb, int budget)
{
 /* Zero budget indicate non-NAPI context called us, like netpoll */
 if (unlikely(!budget)) {
  dev_consume_skb_any(skb);
  return;
 }

 DEBUG_NET_WARN_ON_ONCE(!in_softirq());

 if (!skb_unref(skb))
  return;

 /* if reaching here SKB is ready to free */
 trace_consume_skb(skb, __builtin_return_address(0));

 /* if SKB is a clone, don't handle this case */
 if (skb->fclone != SKB_FCLONE_UNAVAILABLE) {
  __kfree_skb(skb);
  return;
 }

 skb_release_all(skb, SKB_CONSUMED);
 napi_skb_cache_put(skb);
}
EXPORT_SYMBOL(napi_consume_skb);

/* Make sure a field is contained by headers group */
#define CHECK_SKB_FIELD(field) \
 BUILD_BUG_ON(offsetof(struct sk_buff, field) !=  \
       offsetof(struct sk_buff, headers.field)); \

static void __copy_skb_header(struct sk_buff *newconst struct sk_buff *old)
{
 new->tstamp  = old->tstamp;
 /* We do not copy old->sk */
 new->dev  = old->dev;
 memcpy(new->cb, old->cb, sizeof(old->cb));
 skb_dst_copy(new, old);
 __skb_ext_copy(new, old);
 __nf_copy(new, old, false);

 /* Note : this field could be in the headers group.
 * It is not yet because we do not want to have a 16 bit hole
 */

 new->queue_mapping = old->queue_mapping;

 memcpy(&new->headers, &old->headers, sizeof(new->headers));
 CHECK_SKB_FIELD(protocol);
 CHECK_SKB_FIELD(csum);
 CHECK_SKB_FIELD(hash);
 CHECK_SKB_FIELD(priority);
 CHECK_SKB_FIELD(skb_iif);
 CHECK_SKB_FIELD(vlan_proto);
 CHECK_SKB_FIELD(vlan_tci);
 CHECK_SKB_FIELD(transport_header);
 CHECK_SKB_FIELD(network_header);
 CHECK_SKB_FIELD(mac_header);
 CHECK_SKB_FIELD(inner_protocol);
 CHECK_SKB_FIELD(inner_transport_header);
 CHECK_SKB_FIELD(inner_network_header);
 CHECK_SKB_FIELD(inner_mac_header);
 CHECK_SKB_FIELD(mark);
#ifdef CONFIG_NETWORK_SECMARK
 CHECK_SKB_FIELD(secmark);
#endif
#ifdef CONFIG_NET_RX_BUSY_POLL
 CHECK_SKB_FIELD(napi_id);
#endif
 CHECK_SKB_FIELD(alloc_cpu);
#ifdef CONFIG_XPS
 CHECK_SKB_FIELD(sender_cpu);
#endif
#ifdef CONFIG_NET_SCHED
 CHECK_SKB_FIELD(tc_index);
#endif

}

/*
 * You should not add any new code to this function.  Add it to
 * __copy_skb_header above instead.
 */

static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
{
#define C(x) n->x = skb->x

 n->next = n->prev = NULL;
 n->sk = NULL;
 __copy_skb_header(n, skb);

 C(len);
 C(data_len);
 C(mac_len);
 n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
 n->cloned = 1;
 n->nohdr = 0;
 n->peeked = 0;
 C(pfmemalloc);
 C(pp_recycle);
 n->destructor = NULL;
 C(tail);
 C(end);
 C(head);
 C(head_frag);
 C(data);
 C(truesize);
 refcount_set(&n->users, 1);

 atomic_inc(&(skb_shinfo(skb)->dataref));
 skb->cloned = 1;

 return n;
#undef C
}

/**
 * alloc_skb_for_msg() - allocate sk_buff to wrap frag list forming a msg
 * @first: first sk_buff of the msg
 */

struct sk_buff *alloc_skb_for_msg(struct sk_buff *first)
{
 struct sk_buff *n;

 n = alloc_skb(0, GFP_ATOMIC);
 if (!n)
  return NULL;

 n->len = first->len;
 n->data_len = first->len;
 n->truesize = first->truesize;

 skb_shinfo(n)->frag_list = first;

 __copy_skb_header(n, first);
 n->destructor = NULL;

 return n;
}
EXPORT_SYMBOL_GPL(alloc_skb_for_msg);

/**
 * skb_morph - morph one skb into another
 * @dst: the skb to receive the contents
 * @src: the skb to supply the contents
 *
 * This is identical to skb_clone except that the target skb is
 * supplied by the user.
 *
 * The target skb is returned upon exit.
 */

struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
{
 skb_release_all(dst, SKB_CONSUMED);
 return __skb_clone(dst, src);
}
EXPORT_SYMBOL_GPL(skb_morph);

int mm_account_pinned_pages(struct mmpin *mmp, size_t size)
{
 unsigned long max_pg, num_pg, new_pg, old_pg, rlim;
 struct user_struct *user;

 if (capable(CAP_IPC_LOCK) || !size)
  return 0;

 rlim = rlimit(RLIMIT_MEMLOCK);
 if (rlim == RLIM_INFINITY)
  return 0;

 num_pg = (size >> PAGE_SHIFT) + 2; /* worst case */
 max_pg = rlim >> PAGE_SHIFT;
 user = mmp->user ? : current_user();

 old_pg = atomic_long_read(&user->locked_vm);
 do {
  new_pg = old_pg + num_pg;
  if (new_pg > max_pg)
   return -ENOBUFS;
 } while (!atomic_long_try_cmpxchg(&user->locked_vm, &old_pg, new_pg));

 if (!mmp->user) {
  mmp->user = get_uid(user);
  mmp->num_pg = num_pg;
 } else {
  mmp->num_pg += num_pg;
 }

 return 0;
}
EXPORT_SYMBOL_GPL(mm_account_pinned_pages);

void mm_unaccount_pinned_pages(struct mmpin *mmp)
{
 if (mmp->user) {
  atomic_long_sub(mmp->num_pg, &mmp->user->locked_vm);
  free_uid(mmp->user);
 }
}
EXPORT_SYMBOL_GPL(mm_unaccount_pinned_pages);

static struct ubuf_info *msg_zerocopy_alloc(struct sock *sk, size_t size,
         bool devmem)
{
 struct ubuf_info_msgzc *uarg;
 struct sk_buff *skb;

 WARN_ON_ONCE(!in_task());

 skb = sock_omalloc(sk, 0, GFP_KERNEL);
 if (!skb)
  return NULL;

 BUILD_BUG_ON(sizeof(*uarg) > sizeof(skb->cb));
 uarg = (void *)skb->cb;
 uarg->mmp.user = NULL;

 if (likely(!devmem) && mm_account_pinned_pages(&uarg->mmp, size)) {
  kfree_skb(skb);
  return NULL;
 }

 uarg->ubuf.ops = &msg_zerocopy_ubuf_ops;
 uarg->id = ((u32)atomic_inc_return(&sk->sk_zckey)) - 1;
 uarg->len = 1;
 uarg->bytelen = size;
 uarg->zerocopy = 1;
 uarg->ubuf.flags = SKBFL_ZEROCOPY_FRAG | SKBFL_DONT_ORPHAN;
 refcount_set(&uarg->ubuf.refcnt, 1);
 sock_hold(sk);

 return &uarg->ubuf;
}

static inline struct sk_buff *skb_from_uarg(struct ubuf_info_msgzc *uarg)
{
 return container_of((void *)uarg, struct sk_buff, cb);
}

struct ubuf_info *msg_zerocopy_realloc(struct sock *sk, size_t size,
           struct ubuf_info *uarg, bool devmem)
{
 if (uarg) {
  struct ubuf_info_msgzc *uarg_zc;
  const u32 byte_limit = 1 << 19;  /* limit to a few TSO */
  u32 bytelen, next;

  /* there might be non MSG_ZEROCOPY users */
  if (uarg->ops != &msg_zerocopy_ubuf_ops)
   return NULL;

  /* realloc only when socket is locked (TCP, UDP cork),
 * so uarg->len and sk_zckey access is serialized
 */

  if (!sock_owned_by_user(sk)) {
   WARN_ON_ONCE(1);
   return NULL;
  }

  uarg_zc = uarg_to_msgzc(uarg);
  bytelen = uarg_zc->bytelen + size;
  if (uarg_zc->len == USHRT_MAX - 1 || bytelen > byte_limit) {
   /* TCP can create new skb to attach new uarg */
   if (sk->sk_type == SOCK_STREAM)
    goto new_alloc;
   return NULL;
  }

  next = (u32)atomic_read(&sk->sk_zckey);
  if ((u32)(uarg_zc->id + uarg_zc->len) == next) {
   if (likely(!devmem) &&
       mm_account_pinned_pages(&uarg_zc->mmp, size))
    return NULL;
   uarg_zc->len++;
   uarg_zc->bytelen = bytelen;
   atomic_set(&sk->sk_zckey, ++next);

   /* no extra ref when appending to datagram (MSG_MORE) */
   if (sk->sk_type == SOCK_STREAM)
    net_zcopy_get(uarg);

   return uarg;
  }
 }

new_alloc:
 return msg_zerocopy_alloc(sk, size, devmem);
}
EXPORT_SYMBOL_GPL(msg_zerocopy_realloc);

static bool skb_zerocopy_notify_extend(struct sk_buff *skb, u32 lo, u16 len)
{
 struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
 u32 old_lo, old_hi;
 u64 sum_len;

 old_lo = serr->ee.ee_info;
 old_hi = serr->ee.ee_data;
 sum_len = old_hi - old_lo + 1ULL + len;

 if (sum_len >= (1ULL << 32))
  return false;

 if (lo != old_hi + 1)
  return false;

 serr->ee.ee_data += len;
 return true;
}

static void __msg_zerocopy_callback(struct ubuf_info_msgzc *uarg)
{
 struct sk_buff *tail, *skb = skb_from_uarg(uarg);
 struct sock_exterr_skb *serr;
 struct sock *sk = skb->sk;
 struct sk_buff_head *q;
 unsigned long flags;
 bool is_zerocopy;
 u32 lo, hi;
 u16 len;

 mm_unaccount_pinned_pages(&uarg->mmp);

 /* if !len, there was only 1 call, and it was aborted
 * so do not queue a completion notification
 */

 if (!uarg->len || sock_flag(sk, SOCK_DEAD))
  goto release;

 len = uarg->len;
 lo = uarg->id;
 hi = uarg->id + len - 1;
 is_zerocopy = uarg->zerocopy;

 serr = SKB_EXT_ERR(skb);
 memset(serr, 0, sizeof(*serr));
 serr->ee.ee_errno = 0;
 serr->ee.ee_origin = SO_EE_ORIGIN_ZEROCOPY;
 serr->ee.ee_data = hi;
 serr->ee.ee_info = lo;
 if (!is_zerocopy)
  serr->ee.ee_code |= SO_EE_CODE_ZEROCOPY_COPIED;

 q = &sk->sk_error_queue;
 spin_lock_irqsave(&q->lock, flags);
 tail = skb_peek_tail(q);
 if (!tail || SKB_EXT_ERR(tail)->ee.ee_origin != SO_EE_ORIGIN_ZEROCOPY ||
     !skb_zerocopy_notify_extend(tail, lo, len)) {
  __skb_queue_tail(q, skb);
  skb = NULL;
 }
 spin_unlock_irqrestore(&q->lock, flags);

 sk_error_report(sk);

release:
 consume_skb(skb);
 sock_put(sk);
}

static void msg_zerocopy_complete(struct sk_buff *skb, struct ubuf_info *uarg,
      bool success)
{
 struct ubuf_info_msgzc *uarg_zc = uarg_to_msgzc(uarg);

 uarg_zc->zerocopy = uarg_zc->zerocopy & success;

 if (refcount_dec_and_test(&uarg->refcnt))
  __msg_zerocopy_callback(uarg_zc);
}

void msg_zerocopy_put_abort(struct ubuf_info *uarg, bool have_uref)
{
 struct sock *sk = skb_from_uarg(uarg_to_msgzc(uarg))->sk;

 atomic_dec(&sk->sk_zckey);
 uarg_to_msgzc(uarg)->len--;

 if (have_uref)
  msg_zerocopy_complete(NULL, uarg, true);
}
EXPORT_SYMBOL_GPL(msg_zerocopy_put_abort);

const struct ubuf_info_ops msg_zerocopy_ubuf_ops = {
 .complete = msg_zerocopy_complete,
};
EXPORT_SYMBOL_GPL(msg_zerocopy_ubuf_ops);

int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
        struct msghdr *msg, int len,
        struct ubuf_info *uarg,
        struct net_devmem_dmabuf_binding *binding)
{
 int err, orig_len = skb->len;

 if (uarg->ops->link_skb) {
  err = uarg->ops->link_skb(skb, uarg);
  if (err)
   return err;
 } else {
  struct ubuf_info *orig_uarg = skb_zcopy(skb);

  /* An skb can only point to one uarg. This edge case happens
 * when TCP appends to an skb, but zerocopy_realloc triggered
 * a new alloc.
 */

  if (orig_uarg && uarg != orig_uarg)
   return -EEXIST;
 }

 err = __zerocopy_sg_from_iter(msg, sk, skb, &msg->msg_iter, len,
          binding);
 if (err == -EFAULT || (err == -EMSGSIZE && skb->len == orig_len)) {
  struct sock *save_sk = skb->sk;

  /* Streams do not free skb on error. Reset to prev state. */
  iov_iter_revert(&msg->msg_iter, skb->len - orig_len);
  skb->sk = sk;
  ___pskb_trim(skb, orig_len);
  skb->sk = save_sk;
  return err;
 }

 skb_zcopy_set(skb, uarg, NULL);
 return skb->len - orig_len;
}
EXPORT_SYMBOL_GPL(skb_zerocopy_iter_stream);

void __skb_zcopy_downgrade_managed(struct sk_buff *skb)
{
 int i;

 skb_shinfo(skb)->flags &= ~SKBFL_MANAGED_FRAG_REFS;
 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
  skb_frag_ref(skb, i);
}
EXPORT_SYMBOL_GPL(__skb_zcopy_downgrade_managed);

static int skb_zerocopy_clone(struct sk_buff *nskb, struct sk_buff *orig,
         gfp_t gfp_mask)
{
 if (skb_zcopy(orig)) {
  if (skb_zcopy(nskb)) {
   /* !gfp_mask callers are verified to !skb_zcopy(nskb) */
   if (!gfp_mask) {
    WARN_ON_ONCE(1);
    return -ENOMEM;
   }
   if (skb_uarg(nskb) == skb_uarg(orig))
    return 0;
   if (skb_copy_ubufs(nskb, GFP_ATOMIC))
    return -EIO;
  }
  skb_zcopy_set(nskb, skb_uarg(orig), NULL);
 }
 return 0;
}

/**
 * skb_copy_ubufs - copy userspace skb frags buffers to kernel
 * @skb: the skb to modify
 * @gfp_mask: allocation priority
 *
 * This must be called on skb with SKBFL_ZEROCOPY_ENABLE.
 * It will copy all frags into kernel and drop the reference
 * to userspace pages.
 *
 * If this function is called from an interrupt gfp_mask() must be
 * %GFP_ATOMIC.
 *
 * Returns 0 on success or a negative error code on failure
 * to allocate kernel memory to copy to.
 */

int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
{
 int num_frags = skb_shinfo(skb)->nr_frags;
 struct page *page, *head = NULL;
 int i, order, psize, new_frags;
 u32 d_off;

 if (skb_shared(skb) || skb_unclone(skb, gfp_mask))
  return -EINVAL;

 if (!skb_frags_readable(skb))
  return -EFAULT;

 if (!num_frags)
  goto release;

 /* We might have to allocate high order pages, so compute what minimum
 * page order is needed.
 */

 order = 0;
 while ((PAGE_SIZE << order) * MAX_SKB_FRAGS < __skb_pagelen(skb))
  order++;
 psize = (PAGE_SIZE << order);

 new_frags = (__skb_pagelen(skb) + psize - 1) >> (PAGE_SHIFT + order);
 for (i = 0; i < new_frags; i++) {
  page = alloc_pages(gfp_mask | __GFP_COMP, order);
  if (!page) {
   while (head) {
    struct page *next = (struct page *)page_private(head);
    put_page(head);
    head = next;
   }
   return -ENOMEM;
  }
  set_page_private(page, (unsigned long)head);
  head = page;
 }

 page = head;
 d_off = 0;
 for (i = 0; i < num_frags; i++) {
  skb_frag_t *f = &skb_shinfo(skb)->frags[i];
  u32 p_off, p_len, copied;
  struct page *p;
  u8 *vaddr;

  skb_frag_foreach_page(f, skb_frag_off(f), skb_frag_size(f),
          p, p_off, p_len, copied) {
   u32 copy, done = 0;
   vaddr = kmap_atomic(p);

   while (done < p_len) {
    if (d_off == psize) {
     d_off = 0;
     page = (struct page *)page_private(page);
    }
    copy = min_t(u32, psize - d_off, p_len - done);
    memcpy(page_address(page) + d_off,
           vaddr + p_off + done, copy);
    done += copy;
    d_off += copy;
   }
   kunmap_atomic(vaddr);
  }
 }

 /* skb frags release userspace buffers */
 for (i = 0; i < num_frags; i++)
  skb_frag_unref(skb, i);

 /* skb frags point to kernel buffers */
 for (i = 0; i < new_frags - 1; i++) {
  __skb_fill_netmem_desc(skb, i, page_to_netmem(head), 0, psize);
  head = (struct page *)page_private(head);
 }
 __skb_fill_netmem_desc(skb, new_frags - 1, page_to_netmem(head), 0,
          d_off);
 skb_shinfo(skb)->nr_frags = new_frags;

release:
 skb_zcopy_clear(skb, false);
 return 0;
}
EXPORT_SYMBOL_GPL(skb_copy_ubufs);

/**
 * skb_clone - duplicate an sk_buff
 * @skb: buffer to clone
 * @gfp_mask: allocation priority
 *
 * Duplicate an &sk_buff. The new one is not owned by a socket. Both
 * copies share the same packet data but not structure. The new
 * buffer has a reference count of 1. If the allocation fails the
 * function returns %NULL otherwise the new buffer is returned.
 *
 * If this function is called from an interrupt gfp_mask() must be
 * %GFP_ATOMIC.
 */


struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
 struct sk_buff_fclones *fclones = container_of(skb,
             struct sk_buff_fclones,
             skb1);
 struct sk_buff *n;

 if (skb_orphan_frags(skb, gfp_mask))
  return NULL;

 if (skb->fclone == SKB_FCLONE_ORIG &&
     refcount_read(&fclones->fclone_ref) == 1) {
  n = &fclones->skb2;
  refcount_set(&fclones->fclone_ref, 2);
  n->fclone = SKB_FCLONE_CLONE;
 } else {
  if (skb_pfmemalloc(skb))
   gfp_mask |= __GFP_MEMALLOC;

  n = kmem_cache_alloc(net_hotdata.skbuff_cache, gfp_mask);
  if (!n)
   return NULL;

  n->fclone = SKB_FCLONE_UNAVAILABLE;
 }

 return __skb_clone(n, skb);
}
EXPORT_SYMBOL(skb_clone);

void skb_headers_offset_update(struct sk_buff *skb, int off)
{
 /* Only adjust this if it actually is csum_start rather than csum */
 if (skb->ip_summed == CHECKSUM_PARTIAL)
  skb->csum_start += off;
 /* {transport,network,mac}_header and tail are relative to skb->head */
 skb->transport_header += off;
 skb->network_header   += off;
 if (skb_mac_header_was_set(skb))
  skb->mac_header += off;
 skb->inner_transport_header += off;
 skb->inner_network_header += off;
 skb->inner_mac_header += off;
}
EXPORT_SYMBOL(skb_headers_offset_update);

void skb_copy_header(struct sk_buff *newconst struct sk_buff *old)
{
 __copy_skb_header(new, old);

 skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
 skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
}
EXPORT_SYMBOL(skb_copy_header);

static inline int skb_alloc_rx_flag(const struct sk_buff *skb)
{
 if (skb_pfmemalloc(skb))
  return SKB_ALLOC_RX;
 return 0;
}

/**
 * skb_copy - create private copy of an sk_buff
 * @skb: buffer to copy
 * @gfp_mask: allocation priority
 *
 * Make a copy of both an &sk_buff and its data. This is used when the
 * caller wishes to modify the data and needs a private copy of the
 * data to alter. Returns %NULL on failure or the pointer to the buffer
 * on success. The returned buffer has a reference count of 1.
 *
 * As by-product this function converts non-linear &sk_buff to linear
 * one, so that &sk_buff becomes completely private and caller is allowed
 * to modify all the data of returned buffer. This means that this
 * function is not recommended for use in circumstances when only
 * header is going to be modified. Use pskb_copy() instead.
 */


struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
 struct sk_buff *n;
 unsigned int size;
 int headerlen;

 if (!skb_frags_readable(skb))
  return NULL;

 if (WARN_ON_ONCE(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST))
  return NULL;

 headerlen = skb_headroom(skb);
 size = skb_end_offset(skb) + skb->data_len;
 n = __alloc_skb(size, gfp_mask,
   skb_alloc_rx_flag(skb), NUMA_NO_NODE);
 if (!n)
  return NULL;

 /* Set the data pointer */
 skb_reserve(n, headerlen);
 /* Set the tail pointer and length */
 skb_put(n, skb->len);

 BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));

 skb_copy_header(n, skb);
 return n;
}
EXPORT_SYMBOL(skb_copy);

/**
 * __pskb_copy_fclone -  create copy of an sk_buff with private head.
 * @skb: buffer to copy
 * @headroom: headroom of new skb
 * @gfp_mask: allocation priority
 * @fclone: if true allocate the copy of the skb from the fclone
 * cache instead of the head cache; it is recommended to set this
 * to true for the cases where the copy will likely be cloned
 *
 * Make a copy of both an &sk_buff and part of its data, located
 * in header. Fragmented data remain shared. This is used when
 * the caller wishes to modify only header of &sk_buff and needs
 * private copy of the header to alter. Returns %NULL on failure
 * or the pointer to the buffer on success.
 * The returned buffer has a reference count of 1.
 */


struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
       gfp_t gfp_mask, bool fclone)
{
 unsigned int size = skb_headlen(skb) + headroom;
 int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0);
 struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE);

 if (!n)
  goto out;

 /* Set the data pointer */
 skb_reserve(n, headroom);
 /* Set the tail pointer and length */
 skb_put(n, skb_headlen(skb));
 /* Copy the bytes */
 skb_copy_from_linear_data(skb, n->data, n->len);

 n->truesize += skb->data_len;
 n->data_len  = skb->data_len;
 n->len      = skb->len;

 if (skb_shinfo(skb)->nr_frags) {
  int i;

  if (skb_orphan_frags(skb, gfp_mask) ||
      skb_zerocopy_clone(n, skb, gfp_mask)) {
   kfree_skb(n);
   n = NULL;
   goto out;
  }
  for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
   skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
   skb_frag_ref(skb, i);
  }
  skb_shinfo(n)->nr_frags = i;
 }

 if (skb_has_frag_list(skb)) {
  skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
  skb_clone_fraglist(n);
 }

 skb_copy_header(n, skb);
out:
 return n;
}
EXPORT_SYMBOL(__pskb_copy_fclone);

/**
 * pskb_expand_head - reallocate header of &sk_buff
 * @skb: buffer to reallocate
 * @nhead: room to add at head
 * @ntail: room to add at tail
 * @gfp_mask: allocation priority
 *
 * Expands (or creates identical copy, if @nhead and @ntail are zero)
 * header of @skb. &sk_buff itself is not changed. &sk_buff MUST have
 * reference count of 1. Returns zero in the case of success or error,
 * if expansion failed. In the last case, &sk_buff is not changed.
 *
 * All the pointers pointing into skb header may change and must be
 * reloaded after call to this function.
 */


int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
       gfp_t gfp_mask)
{
 unsigned int osize = skb_end_offset(skb);
 unsigned int size = osize + nhead + ntail;
 long off;
 u8 *data;
 int i;

 BUG_ON(nhead < 0);

 BUG_ON(skb_shared(skb));

 skb_zcopy_downgrade_managed(skb);

 if (skb_pfmemalloc(skb))
  gfp_mask |= __GFP_MEMALLOC;

 data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL);
 if (!data)
  goto nodata;
 size = SKB_WITH_OVERHEAD(size);

 /* Copy only real data... and, alas, header. This should be
 * optimized for the cases when header is void.
 */

 memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);

 memcpy((struct skb_shared_info *)(data + size),
        skb_shinfo(skb),
        offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));

 /*
 * if shinfo is shared we must drop the old head gracefully, but if it
 * is not we can just drop the old head and let the existing refcount
 * be since all we did is relocate the values
 */

 if (skb_cloned(skb)) {
  if (skb_orphan_frags(skb, gfp_mask))
   goto nofrags;
  if (skb_zcopy(skb))
   refcount_inc(&skb_uarg(skb)->refcnt);
  for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
   skb_frag_ref(skb, i);

  if (skb_has_frag_list(skb))
   skb_clone_fraglist(skb);

  skb_release_data(skb, SKB_CONSUMED);
 } else {
  skb_free_head(skb);
 }
 off = (data + nhead) - skb->head;

 skb->head     = data;
 skb->head_frag = 0;
 skb->data    += off;

 skb_set_end_offset(skb, size);
#ifdef NET_SKBUFF_DATA_USES_OFFSET
 off           = nhead;
#endif
 skb->tail       += off;
 skb_headers_offset_update(skb, nhead);
 skb->cloned   = 0;
 skb->hdr_len  = 0;
 skb->nohdr    = 0;
 atomic_set(&skb_shinfo(skb)->dataref, 1);

 skb_metadata_clear(skb);

 /* It is not generally safe to change skb->truesize.
 * For the moment, we really care of rx path, or
 * when skb is orphaned (not attached to a socket).
 */

 if (!skb->sk || skb->destructor == sock_edemux)
  skb->truesize += size - osize;

 return 0;

nofrags:
 skb_kfree_head(data, size);
nodata:
 return -ENOMEM;
}
EXPORT_SYMBOL(pskb_expand_head);

/* Make private copy of skb with writable head and some headroom */

struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
{
 struct sk_buff *skb2;
 int delta = headroom - skb_headroom(skb);

 if (delta <= 0)
  skb2 = pskb_copy(skb, GFP_ATOMIC);
 else {
  skb2 = skb_clone(skb, GFP_ATOMIC);
  if (skb2 && pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0,
          GFP_ATOMIC)) {
   kfree_skb(skb2);
   skb2 = NULL;
  }
 }
 return skb2;
}
EXPORT_SYMBOL(skb_realloc_headroom);

/* Note: We plan to rework this in linux-6.4 */
int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri)
{
 unsigned int saved_end_offset, saved_truesize;
 struct skb_shared_info *shinfo;
 int res;

 saved_end_offset = skb_end_offset(skb);
 saved_truesize = skb->truesize;

 res = pskb_expand_head(skb, 0, 0, pri);
 if (res)
  return res;

 skb->truesize = saved_truesize;

 if (likely(skb_end_offset(skb) == saved_end_offset))
  return 0;

 /* We can not change skb->end if the original or new value
 * is SKB_SMALL_HEAD_HEADROOM, as it might break skb_kfree_head().
 */

 if (saved_end_offset == SKB_SMALL_HEAD_HEADROOM ||
     skb_end_offset(skb) == SKB_SMALL_HEAD_HEADROOM) {
  /* We think this path should not be taken.
 * Add a temporary trace to warn us just in case.
 */

  pr_err_once("__skb_unclone_keeptruesize() skb_end_offset() %u -> %u\n",
       saved_end_offset, skb_end_offset(skb));
  WARN_ON_ONCE(1);
  return 0;
 }

 shinfo = skb_shinfo(skb);

 /* We are about to change back skb->end,
 * we need to move skb_shinfo() to its new location.
 */

 memmove(skb->head + saved_end_offset,
  shinfo,
  offsetof(struct skb_shared_info, frags[shinfo->nr_frags]));

 skb_set_end_offset(skb, saved_end_offset);

 return 0;
}

/**
 * skb_expand_head - reallocate header of &sk_buff
 * @skb: buffer to reallocate
 * @headroom: needed headroom
 *
 * Unlike skb_realloc_headroom, this one does not allocate a new skb
 * if possible; copies skb->sk to new skb as needed
 * and frees original skb in case of failures.
 *
 * It expect increased headroom and generates warning otherwise.
 */


struct sk_buff *skb_expand_head(struct sk_buff *skb, unsigned int headroom)
{
 int delta = headroom - skb_headroom(skb);
 int osize = skb_end_offset(skb);
 struct sock *sk = skb->sk;

 if (WARN_ONCE(delta <= 0,
        "%s is expecting an increase in the headroom", __func__))
  return skb;

 delta = SKB_DATA_ALIGN(delta);
 /* pskb_expand_head() might crash, if skb is shared. */
 if (skb_shared(skb) || !is_skb_wmem(skb)) {
  struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);

  if (unlikely(!nskb))
   goto fail;

  if (sk)
   skb_set_owner_w(nskb, sk);
  consume_skb(skb);
  skb = nskb;
 }
 if (pskb_expand_head(skb, delta, 0, GFP_ATOMIC))
  goto fail;

 if (sk && is_skb_wmem(skb)) {
  delta = skb_end_offset(skb) - osize;
  refcount_add(delta, &sk->sk_wmem_alloc);
  skb->truesize += delta;
 }
 return skb;

fail:
 kfree_skb(skb);
 return NULL;
}
EXPORT_SYMBOL(skb_expand_head);

/**
 * skb_copy_expand - copy and expand sk_buff
 * @skb: buffer to copy
 * @newheadroom: new free bytes at head
 * @newtailroom: new free bytes at tail
 * @gfp_mask: allocation priority
 *
 * Make a copy of both an &sk_buff and its data and while doing so
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.