blob: c93c87caa08b69361a4af597d00a685362830717 [file] [log] [blame]
/*
* Copyright (c) 2013-2017, 2022, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* Definitions for the skb recycler functions */
#ifndef _LINUX_SKBUFF_RECYCLE_H
#define _LINUX_SKBUFF_RECYCLE_H
#include <linux/module.h>
#include <linux/types.h>
#include <linux/cpu.h>
#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/netdevice.h>
#ifdef CONFIG_NET_CLS_ACT
#include <net/pkt_sched.h>
#endif
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/splice.h>
#include <linux/init.h>
#include <linux/prefetch.h>
#include <linux/if.h>
#define SKB_RECYCLE_SIZE 2304
#define SKB_RECYCLE_MIN_SIZE SKB_RECYCLE_SIZE
#define SKB_RECYCLE_MAX_SIZE (3904 - NET_SKB_PAD)
#define SKB_RECYCLE_MAX_SKBS 8192
#define SKB_RECYCLE_SPARE_MAX_SKBS 256
#ifdef CONFIG_SKB_RECYCLER_PREALLOC
#define SKB_RECYCLE_MAX_PREALLOC_SKBS CONFIG_SKB_RECYCLE_MAX_PREALLOC_SKBS
#define SKB_RECYCLE_MAX_SHARED_POOLS \
DIV_ROUND_UP(SKB_RECYCLE_MAX_PREALLOC_SKBS, \
SKB_RECYCLE_SPARE_MAX_SKBS)
#else
#define SKB_RECYCLE_MAX_SHARED_POOLS 8
#endif
#define SKB_RECYCLE_MAX_SHARED_POOLS_MASK \
(SKB_RECYCLE_MAX_SHARED_POOLS - 1)
#ifdef CONFIG_SKB_RECYCLER_MULTI_CPU
struct global_recycler {
/* Global circular list which holds the shared skb pools */
struct sk_buff_head pool[SKB_RECYCLE_MAX_SHARED_POOLS];
u8 head; /* head of the circular list */
u8 tail; /* tail of the circular list */
spinlock_t lock;
};
#endif
static __always_inline void zero_struct(void *v, int size)
{
u32 *s = (u32 *)v;
/* We assume that size is word aligned; in fact, it's constant */
WARN_ON((size & 3) != 0);
/* This looks odd but we "know" size is a constant, and so the
* compiler can fold away all of the conditionals. The compiler is
* pretty smart here, and can fold away the loop, too!
*/
while (size > 0) {
if (size >= 4)
s[0] = 0;
if (size >= 8)
s[1] = 0;
if (size >= 12)
s[2] = 0;
if (size >= 16)
s[3] = 0;
if (size >= 20)
s[4] = 0;
if (size >= 24)
s[5] = 0;
if (size >= 28)
s[6] = 0;
if (size >= 32)
s[7] = 0;
if (size >= 36)
s[8] = 0;
if (size >= 40)
s[9] = 0;
if (size >= 44)
s[10] = 0;
if (size >= 48)
s[11] = 0;
if (size >= 52)
s[12] = 0;
if (size >= 56)
s[13] = 0;
if (size >= 60)
s[14] = 0;
if (size >= 64)
s[15] = 0;
size -= 64;
s += 16;
}
}
static inline bool consume_skb_can_recycle(const struct sk_buff *skb,
int min_skb_size, int max_skb_size)
{
if (unlikely(irqs_disabled()))
return false;
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY))
return false;
if (unlikely(skb_is_nonlinear(skb)))
return false;
if (unlikely(skb_shinfo(skb)->frag_list))
return false;
if (unlikely(skb_shinfo(skb)->nr_frags))
return false;
if (unlikely(skb->fclone != SKB_FCLONE_UNAVAILABLE))
return false;
min_skb_size = SKB_DATA_ALIGN(min_skb_size + NET_SKB_PAD);
if (unlikely(skb_end_pointer(skb) - skb->head < min_skb_size))
return false;
max_skb_size = SKB_DATA_ALIGN(max_skb_size + NET_SKB_PAD);
if (unlikely(skb_end_pointer(skb) - skb->head > max_skb_size))
return false;
if (unlikely(skb_cloned(skb)))
return false;
if (unlikely(skb_pfmemalloc(skb)))
return false;
return true;
}
#ifdef CONFIG_SKB_RECYCLER
void __init skb_recycler_init(void);
struct sk_buff *skb_recycler_alloc(struct net_device *dev, unsigned int length);
bool skb_recycler_consume(struct sk_buff *skb);
void skb_recycler_print_all_lists(void);
#else
#define skb_recycler_init() {}
#define skb_recycler_alloc(dev, len) NULL
#define skb_recycler_consume(skb) false
#define skb_recycler_print_all_lists() false
#endif
#endif