1/*
2 * Copyright (c) 2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#ifndef _SKYWALK_NEXUS_PKTQ_H_
29#define _SKYWALK_NEXUS_PKTQ_H_
30
31#include <kern/locks.h>
32#include <net/classq/classq.h>
33
34#define NX_PKTQ_NO_LIMIT ((uint32_t)-1)
35
36/*
37 * These function implement an packet tailq with an optional lock.
38 * The base functions act ONLY ON THE QUEUE, whereas the "safe"
39 * variants (nx_pktq_safe_*) also handle the lock.
40 */
41
42/* A FIFO queue of packets with an optional lock. */
43struct nx_pktq {
44 decl_lck_mtx_data(, nx_pktq_lock);
45 class_queue_t nx_pktq_q;
46 lck_grp_t *nx_pktq_grp;
47 struct __kern_channel_ring *nx_pktq_kring;
48};
49
50__attribute__((always_inline))
51static inline void
52nx_pktq_lock(struct nx_pktq *q)
53{
54 lck_mtx_lock(lck: &q->nx_pktq_lock);
55}
56
57__attribute__((always_inline))
58static inline void
59nx_pktq_lock_spin(struct nx_pktq *q)
60{
61 lck_mtx_lock_spin(lck: &q->nx_pktq_lock);
62}
63
64__attribute__((always_inline))
65static inline void
66nx_pktq_convert_spin(struct nx_pktq *q)
67{
68 lck_mtx_convert_spin(lck: &q->nx_pktq_lock);
69}
70
71__attribute__((always_inline))
72static inline void
73nx_pktq_unlock(struct nx_pktq *q)
74{
75 lck_mtx_unlock(lck: &q->nx_pktq_lock);
76}
77
78__attribute__((always_inline))
79static inline struct __kern_packet *
80nx_pktq_peek(struct nx_pktq *q)
81{
82 return qhead(&q->nx_pktq_q);
83}
84
85__attribute__((always_inline))
86static inline unsigned int
87nx_pktq_len(struct nx_pktq *q)
88{
89 return qlen(&q->nx_pktq_q);
90}
91
92__attribute__((always_inline))
93static inline size_t
94nx_pktq_size(struct nx_pktq *q)
95{
96 u_int64_t qsize = qsize(&q->nx_pktq_q);
97 VERIFY(qsize <= UINT_MAX);
98 return (size_t)qsize;
99}
100
101__attribute__((always_inline))
102static inline unsigned int
103nx_pktq_limit(struct nx_pktq *q)
104{
105 return qlimit(&q->nx_pktq_q);
106}
107
108__attribute__((always_inline))
109static inline void
110__nx_pktq_enq(struct nx_pktq *q, struct __kern_packet *p)
111{
112 classq_pkt_t pkt;
113
114 CLASSQ_PKT_INIT_PACKET(&pkt, p);
115 _addq(&q->nx_pktq_q, &pkt);
116}
117
118__attribute__((always_inline))
119static inline void
120nx_pktq_safe_enq(struct nx_pktq *q, struct __kern_packet *p)
121{
122 nx_pktq_lock(q);
123 __nx_pktq_enq(q, p);
124 nx_pktq_unlock(q);
125}
126
127__attribute__((always_inline))
128static inline void
129nx_pktq_enq(struct nx_pktq *q, struct __kern_packet *p)
130{
131 __nx_pktq_enq(q, p);
132}
133
134__attribute__((always_inline))
135static inline void
136__nx_pktq_enq_multi(struct nx_pktq *q, struct __kern_packet *p_head,
137 struct __kern_packet *p_tail,
138 uint32_t cnt, uint32_t size)
139{
140 classq_pkt_t head, tail;
141
142 CLASSQ_PKT_INIT_PACKET(&head, p_head);
143 CLASSQ_PKT_INIT_PACKET(&tail, p_tail);
144 _addq_multi(&q->nx_pktq_q, &head, &tail, cnt, size);
145}
146
147__attribute__((always_inline))
148static inline void
149nx_pktq_safe_enq_multi(struct nx_pktq *q, struct __kern_packet *p_head,
150 struct __kern_packet *p_tail, uint32_t cnt, uint32_t size)
151{
152 nx_pktq_lock(q);
153 __nx_pktq_enq_multi(q, p_head, p_tail, cnt, size);
154 nx_pktq_unlock(q);
155}
156
157__attribute__((always_inline))
158static inline void
159nx_pktq_enq_multi(struct nx_pktq *q, struct __kern_packet *p_head,
160 struct __kern_packet *p_tail, uint32_t cnt, uint32_t size)
161{
162 __nx_pktq_enq_multi(q, p_head, p_tail, cnt, size);
163}
164
165__attribute__((always_inline))
166static inline struct __kern_packet *
167__pktq_deq(struct nx_pktq *q)
168{
169 classq_pkt_t pkt = CLASSQ_PKT_INITIALIZER(pkt);
170
171 _getq(&q->nx_pktq_q, &pkt);
172 ASSERT((pkt.cp_kpkt == NULL) || (pkt.cp_ptype == QP_PACKET));
173 return pkt.cp_kpkt;
174}
175
176__attribute__((always_inline))
177static inline struct __kern_packet *
178nx_pktq_safe_deq(struct nx_pktq *q)
179{
180 struct __kern_packet *__single ret;
181
182 nx_pktq_lock(q);
183 ret = __pktq_deq(q);
184 nx_pktq_unlock(q);
185
186 return ret;
187}
188
189__attribute__((always_inline))
190static inline struct __kern_packet *
191nx_pktq_deq(struct nx_pktq *q)
192{
193 return __pktq_deq(q);
194}
195
196__attribute__((always_inline))
197static inline struct __kern_packet *
198__pktq_deq_all(struct nx_pktq *q, struct __kern_packet **plast, uint32_t *qlenp,
199 uint64_t *qsizep)
200{
201 classq_pkt_t first = CLASSQ_PKT_INITIALIZER(first);
202 classq_pkt_t last = CLASSQ_PKT_INITIALIZER(last);
203
204 _getq_all(&q->nx_pktq_q, &first, &last, qlenp, qsizep);
205 *plast = last.cp_kpkt;
206 ASSERT((first.cp_kpkt == NULL) || (first.cp_ptype == QP_PACKET));
207 return first.cp_kpkt;
208}
209
210__attribute__((always_inline))
211static inline struct __kern_packet *
212nx_pktq_safe_deq_all(struct nx_pktq *q, struct __kern_packet **last,
213 uint32_t *qlenp, uint64_t *qsizep)
214{
215 struct __kern_packet *__single ret;
216
217 nx_pktq_lock(q);
218 ret = __pktq_deq_all(q, plast: last, qlenp, qsizep);
219 nx_pktq_unlock(q);
220
221 return ret;
222}
223
224__attribute__((always_inline))
225static inline struct __kern_packet *
226nx_pktq_deq_all(struct nx_pktq *q, struct __kern_packet **last, uint32_t *qlenp,
227 uint64_t *qsizep)
228{
229 return __pktq_deq_all(q, plast: last, qlenp, qsizep);
230}
231
232__BEGIN_DECLS
233extern void nx_pktq_init(struct nx_pktq *q, uint32_t lim);
234extern void nx_pktq_concat(struct nx_pktq *q1, struct nx_pktq *q2);
235extern boolean_t nx_pktq_empty(struct nx_pktq *q);
236extern void nx_pktq_destroy(struct nx_pktq *q);
237extern void nx_pktq_purge(struct nx_pktq *q);
238
239extern void nx_pktq_safe_init(struct __kern_channel_ring *kr, struct nx_pktq *q,
240 uint32_t lim, lck_grp_t *lck_grp, lck_attr_t *lck_attr);
241extern void nx_pktq_safe_destroy(struct nx_pktq *q);
242extern void nx_pktq_safe_purge(struct nx_pktq *q);
243__END_DECLS
244#endif /* _SKYWALK_NEXUS_PKTQ_H_ */
245