| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 
|---|
| 2 | /* | 
|---|
| 3 | *	Definitions for the 'struct skb_array' datastructure. | 
|---|
| 4 | * | 
|---|
| 5 | *	Author: | 
|---|
| 6 | *		Michael S. Tsirkin <mst@redhat.com> | 
|---|
| 7 | * | 
|---|
| 8 | *	Copyright (C) 2016 Red Hat, Inc. | 
|---|
| 9 | * | 
|---|
| 10 | *	Limited-size FIFO of skbs. Can be used more or less whenever | 
|---|
| 11 | *	sk_buff_head can be used, except you need to know the queue size in | 
|---|
| 12 | *	advance. | 
|---|
| 13 | *	Implemented as a type-safe wrapper around ptr_ring. | 
|---|
| 14 | */ | 
|---|
| 15 |  | 
|---|
| 16 | #ifndef _LINUX_SKB_ARRAY_H | 
|---|
| 17 | #define _LINUX_SKB_ARRAY_H 1 | 
|---|
| 18 |  | 
|---|
| 19 | #ifdef __KERNEL__ | 
|---|
| 20 | #include <linux/ptr_ring.h> | 
|---|
| 21 | #include <linux/skbuff.h> | 
|---|
| 22 | #include <linux/if_vlan.h> | 
|---|
| 23 | #endif | 
|---|
| 24 |  | 
|---|
| 25 | struct skb_array { | 
|---|
| 26 | struct ptr_ring ring; | 
|---|
| 27 | }; | 
|---|
| 28 |  | 
|---|
| 29 | /* Might be slightly faster than skb_array_full below, but callers invoking | 
|---|
| 30 | * this in a loop must use a compiler barrier, for example cpu_relax(). | 
|---|
| 31 | */ | 
|---|
| 32 | static inline bool __skb_array_full(struct skb_array *a) | 
|---|
| 33 | { | 
|---|
| 34 | return __ptr_ring_full(r: &a->ring); | 
|---|
| 35 | } | 
|---|
| 36 |  | 
|---|
| 37 | static inline bool skb_array_full(struct skb_array *a) | 
|---|
| 38 | { | 
|---|
| 39 | return ptr_ring_full(r: &a->ring); | 
|---|
| 40 | } | 
|---|
| 41 |  | 
|---|
| 42 | static inline int skb_array_produce(struct skb_array *a, struct sk_buff *skb) | 
|---|
| 43 | { | 
|---|
| 44 | return ptr_ring_produce(r: &a->ring, ptr: skb); | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | static inline int skb_array_produce_irq(struct skb_array *a, struct sk_buff *skb) | 
|---|
| 48 | { | 
|---|
| 49 | return ptr_ring_produce_irq(r: &a->ring, ptr: skb); | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | static inline int skb_array_produce_bh(struct skb_array *a, struct sk_buff *skb) | 
|---|
| 53 | { | 
|---|
| 54 | return ptr_ring_produce_bh(r: &a->ring, ptr: skb); | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | static inline int skb_array_produce_any(struct skb_array *a, struct sk_buff *skb) | 
|---|
| 58 | { | 
|---|
| 59 | return ptr_ring_produce_any(r: &a->ring, ptr: skb); | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | /* Might be slightly faster than skb_array_empty below, but only safe if the | 
|---|
| 63 | * array is never resized. Also, callers invoking this in a loop must take care | 
|---|
| 64 | * to use a compiler barrier, for example cpu_relax(). | 
|---|
| 65 | */ | 
|---|
| 66 | static inline bool __skb_array_empty(struct skb_array *a) | 
|---|
| 67 | { | 
|---|
| 68 | return __ptr_ring_empty(r: &a->ring); | 
|---|
| 69 | } | 
|---|
| 70 |  | 
|---|
| 71 | static inline struct sk_buff *__skb_array_peek(struct skb_array *a) | 
|---|
| 72 | { | 
|---|
| 73 | return __ptr_ring_peek(r: &a->ring); | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | static inline bool skb_array_empty(struct skb_array *a) | 
|---|
| 77 | { | 
|---|
| 78 | return ptr_ring_empty(r: &a->ring); | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | static inline bool skb_array_empty_bh(struct skb_array *a) | 
|---|
| 82 | { | 
|---|
| 83 | return ptr_ring_empty_bh(r: &a->ring); | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 86 | static inline bool skb_array_empty_irq(struct skb_array *a) | 
|---|
| 87 | { | 
|---|
| 88 | return ptr_ring_empty_irq(r: &a->ring); | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | static inline bool skb_array_empty_any(struct skb_array *a) | 
|---|
| 92 | { | 
|---|
| 93 | return ptr_ring_empty_any(r: &a->ring); | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | static inline struct sk_buff *__skb_array_consume(struct skb_array *a) | 
|---|
| 97 | { | 
|---|
| 98 | return __ptr_ring_consume(r: &a->ring); | 
|---|
| 99 | } | 
|---|
| 100 |  | 
|---|
| 101 | static inline struct sk_buff *skb_array_consume(struct skb_array *a) | 
|---|
| 102 | { | 
|---|
| 103 | return ptr_ring_consume(r: &a->ring); | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | static inline int skb_array_consume_batched(struct skb_array *a, | 
|---|
| 107 | struct sk_buff **array, int n) | 
|---|
| 108 | { | 
|---|
| 109 | return ptr_ring_consume_batched(r: &a->ring, array: (void **)array, n); | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | static inline struct sk_buff *skb_array_consume_irq(struct skb_array *a) | 
|---|
| 113 | { | 
|---|
| 114 | return ptr_ring_consume_irq(r: &a->ring); | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 | static inline int skb_array_consume_batched_irq(struct skb_array *a, | 
|---|
| 118 | struct sk_buff **array, int n) | 
|---|
| 119 | { | 
|---|
| 120 | return ptr_ring_consume_batched_irq(r: &a->ring, array: (void **)array, n); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | static inline struct sk_buff *skb_array_consume_any(struct skb_array *a) | 
|---|
| 124 | { | 
|---|
| 125 | return ptr_ring_consume_any(r: &a->ring); | 
|---|
| 126 | } | 
|---|
| 127 |  | 
|---|
| 128 | static inline int skb_array_consume_batched_any(struct skb_array *a, | 
|---|
| 129 | struct sk_buff **array, int n) | 
|---|
| 130 | { | 
|---|
| 131 | return ptr_ring_consume_batched_any(r: &a->ring, array: (void **)array, n); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 |  | 
|---|
| 135 | static inline struct sk_buff *skb_array_consume_bh(struct skb_array *a) | 
|---|
| 136 | { | 
|---|
| 137 | return ptr_ring_consume_bh(r: &a->ring); | 
|---|
| 138 | } | 
|---|
| 139 |  | 
|---|
| 140 | static inline int skb_array_consume_batched_bh(struct skb_array *a, | 
|---|
| 141 | struct sk_buff **array, int n) | 
|---|
| 142 | { | 
|---|
| 143 | return ptr_ring_consume_batched_bh(r: &a->ring, array: (void **)array, n); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | static inline int __skb_array_len_with_tag(struct sk_buff *skb) | 
|---|
| 147 | { | 
|---|
| 148 | if (likely(skb)) { | 
|---|
| 149 | int len = skb->len; | 
|---|
| 150 |  | 
|---|
| 151 | if (skb_vlan_tag_present(skb)) | 
|---|
| 152 | len += VLAN_HLEN; | 
|---|
| 153 |  | 
|---|
| 154 | return len; | 
|---|
| 155 | } else { | 
|---|
| 156 | return 0; | 
|---|
| 157 | } | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | static inline int skb_array_peek_len(struct skb_array *a) | 
|---|
| 161 | { | 
|---|
| 162 | return PTR_RING_PEEK_CALL(&a->ring, __skb_array_len_with_tag); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | static inline int skb_array_peek_len_irq(struct skb_array *a) | 
|---|
| 166 | { | 
|---|
| 167 | return PTR_RING_PEEK_CALL_IRQ(&a->ring, __skb_array_len_with_tag); | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | static inline int skb_array_peek_len_bh(struct skb_array *a) | 
|---|
| 171 | { | 
|---|
| 172 | return PTR_RING_PEEK_CALL_BH(&a->ring, __skb_array_len_with_tag); | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | static inline int skb_array_peek_len_any(struct skb_array *a) | 
|---|
| 176 | { | 
|---|
| 177 | return PTR_RING_PEEK_CALL_ANY(&a->ring, __skb_array_len_with_tag); | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | static inline int skb_array_init_noprof(struct skb_array *a, int size, gfp_t gfp) | 
|---|
| 181 | { | 
|---|
| 182 | return ptr_ring_init_noprof(r: &a->ring, size, gfp); | 
|---|
| 183 | } | 
|---|
| 184 | #define skb_array_init(...)	alloc_hooks(skb_array_init_noprof(__VA_ARGS__)) | 
|---|
| 185 |  | 
|---|
| 186 | static void __skb_array_destroy_skb(void *ptr) | 
|---|
| 187 | { | 
|---|
| 188 | kfree_skb(skb: ptr); | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 | static inline void skb_array_unconsume(struct skb_array *a, | 
|---|
| 192 | struct sk_buff **skbs, int n) | 
|---|
| 193 | { | 
|---|
| 194 | ptr_ring_unconsume(r: &a->ring, batch: (void **)skbs, n, destroy: __skb_array_destroy_skb); | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | static inline int skb_array_resize(struct skb_array *a, int size, gfp_t gfp) | 
|---|
| 198 | { | 
|---|
| 199 | return ptr_ring_resize(&a->ring, size, gfp, __skb_array_destroy_skb); | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | static inline int skb_array_resize_multiple_bh_noprof(struct skb_array **rings, | 
|---|
| 203 | int nrings, | 
|---|
| 204 | unsigned int size, | 
|---|
| 205 | gfp_t gfp) | 
|---|
| 206 | { | 
|---|
| 207 | BUILD_BUG_ON(offsetof(struct skb_array, ring)); | 
|---|
| 208 | return ptr_ring_resize_multiple_bh_noprof(rings: (struct ptr_ring **)rings, | 
|---|
| 209 | nrings, size, gfp, | 
|---|
| 210 | destroy: __skb_array_destroy_skb); | 
|---|
| 211 | } | 
|---|
| 212 | #define skb_array_resize_multiple_bh(...)	\ | 
|---|
| 213 | alloc_hooks(skb_array_resize_multiple_bh_noprof(__VA_ARGS__)) | 
|---|
| 214 |  | 
|---|
| 215 | static inline void skb_array_cleanup(struct skb_array *a) | 
|---|
| 216 | { | 
|---|
| 217 | ptr_ring_cleanup(r: &a->ring, destroy: __skb_array_destroy_skb); | 
|---|
| 218 | } | 
|---|
| 219 |  | 
|---|
| 220 | #endif /* _LINUX_SKB_ARRAY_H  */ | 
|---|
| 221 |  | 
|---|