net/core/skbuff.c

Source file repositories/reference/linux-study-clean/net/core/skbuff.c

File Facts

System
Linux kernel
Corpus path
net/core/skbuff.c
Extension
.c
Size
192030 bytes
Lines
7526
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

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);

/* Cache kmem_cache_size(net_hotdata.skbuff_cache) to help the compiler
 * remove dead code (and skbuff_cache_size) when CONFIG_KASAN is unset.
 */
static u32 skbuff_cache_size __read_mostly;

static inline struct sk_buff *napi_skb_cache_get(bool alloc)
{
	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)) {
		if (alloc && kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
						   GFP_ATOMIC | __GFP_NOWARN,
						   NAPI_SKB_CACHE_BULK,
						   nc->skb_cache))
			nc->skb_count = NAPI_SKB_CACHE_BULK;
		if (unlikely(!nc->skb_count)) {
			local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
			return NULL;
		}
	}

	skb = nc->skb_cache[--nc->skb_count];
	if (nc->skb_count)
		prefetch(nc->skb_cache[nc->skb_count - 1]);
	local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
	kasan_mempool_unpoison_object(skb, skbuff_cache_size);

	return skb;
}

/*
 * Only clear those fields we need to clear, not those that we will
 * actually initialise later. Hence, don't put any more fields after
 * the tail pointer in struct sk_buff!
 */
static inline void skbuff_clear(struct sk_buff *skb)
{
	/* Replace memset(skb, 0, offsetof(struct sk_buff, tail))
	 * with two smaller memset(), with a barrier() between them.
	 * This forces the compiler to inline both calls.

Annotation

Implementation Notes