xref: /xnu-8792.61.2/bsd/net/classq/if_classq.h (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2011-2020 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 
29 #ifndef _NET_CLASSQ_IF_CLASSQ_H_
30 #define _NET_CLASSQ_IF_CLASSQ_H_
31 
32 #ifdef PRIVATE
33 #define IFCQ_SC_MAX             10              /* max number of queues */
34 
35 #ifdef BSD_KERNEL_PRIVATE
36 #include <net/classq/classq.h>
37 
38 /* maximum number of packets stored across all queues */
39 #define IFCQ_DEFAULT_PKT_DROP_LIMIT     2048
40 
41 /* classq request types */
42 typedef enum cqrq {
43 	CLASSQRQ_PURGE =        1,      /* purge all packets */
44 	CLASSQRQ_PURGE_SC =     2,      /* purge service class (and flow) */
45 	CLASSQRQ_EVENT =        3,      /* interface events */
46 	CLASSQRQ_THROTTLE =     4,      /* throttle packets */
47 	CLASSQRQ_STAT_SC =      5,      /* get service class queue stats */
48 } cqrq_t;
49 
50 /* classq purge_sc request argument */
51 typedef struct cqrq_purge_sc {
52 	mbuf_svc_class_t        sc;     /* (in) service class */
53 	u_int32_t               flow;   /* (in) 0 means all flows */
54 	u_int32_t               packets; /* (out) purged packets */
55 	u_int32_t               bytes;  /* (out) purged bytes */
56 } cqrq_purge_sc_t;
57 
58 /* classq throttle request argument */
59 typedef struct cqrq_throttle {
60 	u_int32_t               set;    /* set or get */
61 	u_int32_t               level;  /* (in/out) throttling level */
62 } cqrq_throttle_t;
63 
64 /* classq service class stats request argument */
65 typedef struct cqrq_stat_sc {
66 	mbuf_svc_class_t        sc;     /* (in) service class */
67 	u_int8_t                grp_idx; /* group index */
68 	u_int32_t               packets; /* (out) packets enqueued */
69 	u_int32_t               bytes;  /* (out) bytes enqueued */
70 } cqrq_stat_sc_t;
71 
72 /*
73  * A token-bucket regulator limits the rate that a network driver can
74  * dequeue packets from the output queue.  Modern cards are able to buffer
75  * a large amount of packets and dequeue too many packets at a time.  This
76  * bursty dequeue behavior makes it impossible to schedule packets by
77  * queueing disciplines.  A token-bucket is used to control the burst size
78  * in a device independent manner.
79  */
80 struct tb_regulator {
81 	u_int64_t       tbr_rate_raw;   /* (unscaled) token bucket rate */
82 	u_int32_t       tbr_percent;    /* token bucket rate in percentage */
83 	int64_t         tbr_rate;       /* (scaled) token bucket rate */
84 	int64_t         tbr_depth;      /* (scaled) token bucket depth */
85 
86 	int64_t         tbr_token;      /* (scaled) current token */
87 	int64_t         tbr_filluptime; /* (scaled) time to fill up bucket */
88 	u_int64_t       tbr_last;       /* last time token was updated */
89 
90 	/*   needed for poll-and-dequeue */
91 };
92 
93 /* simple token bucket meter profile */
94 struct tb_profile {
95 	u_int64_t       rate;   /* rate in bit-per-sec */
96 	u_int32_t       percent; /* rate in percentage */
97 	u_int32_t       depth;  /* depth in bytes */
98 };
99 
100 struct ifclassq;
101 enum cqdq_op;
102 enum cqrq;
103 
104 #if DEBUG || DEVELOPMENT
105 extern uint32_t ifclassq_flow_control_adv;
106 #endif /* DEBUG || DEVELOPMENT */
107 extern uint32_t ifclassq_enable_l4s;
108 typedef int (*ifclassq_enq_func)(struct ifclassq *, classq_pkt_t *,
109     boolean_t *);
110 typedef void  (*ifclassq_deq_func)(struct ifclassq *, classq_pkt_t *);
111 typedef void (*ifclassq_deq_sc_func)(struct ifclassq *, mbuf_svc_class_t,
112     classq_pkt_t *);
113 typedef int (*ifclassq_deq_multi_func)(struct ifclassq *, u_int32_t,
114     u_int32_t, classq_pkt_t *, classq_pkt_t *, u_int32_t *, u_int32_t *);
115 typedef int (*ifclassq_deq_sc_multi_func)(struct ifclassq *,
116     mbuf_svc_class_t, u_int32_t, u_int32_t, classq_pkt_t *, classq_pkt_t *,
117     u_int32_t *, u_int32_t *);
118 typedef int (*ifclassq_req_func)(struct ifclassq *, enum cqrq, void *);
119 
120 /*
121  * Structure defining a queue for a network interface.
122  */
123 struct ifclassq {
124 	decl_lck_mtx_data(, ifcq_lock);
125 
126 	os_refcnt_t     ifcq_refcnt;
127 	struct ifnet    *ifcq_ifp;      /* back pointer to interface */
128 	u_int32_t       ifcq_len;       /* packet count */
129 	u_int32_t       ifcq_maxlen;
130 	struct pktcntr  ifcq_xmitcnt;
131 	struct pktcntr  ifcq_dropcnt;
132 
133 	u_int32_t       ifcq_type;      /* scheduler type */
134 	u_int32_t       ifcq_flags;     /* flags */
135 	u_int32_t       ifcq_sflags;    /* scheduler flags */
136 	u_int32_t       ifcq_target_qdelay; /* target queue delay */
137 	u_int32_t       ifcq_bytes;     /* bytes count */
138 	u_int32_t       ifcq_pkt_drop_limit;
139 	void            *ifcq_disc;     /* for scheduler-specific use */
140 	/*
141 	 * ifcq_disc_slots[] represents the leaf classes configured for the
142 	 * corresponding discpline/scheduler, ordered by their corresponding
143 	 * service class index.  Each slot holds the queue ID used to identify
144 	 * the class instance, as well as the class instance pointer itself.
145 	 * The latter is used during enqueue and dequeue in order to avoid the
146 	 * costs associated with looking up the class pointer based on the
147 	 * queue ID.  The queue ID is used when querying the statistics from
148 	 * user space.
149 	 *
150 	 * Avoiding the use of queue ID during enqueue and dequeue is made
151 	 * possible by virtue of knowing the particular mbuf service class
152 	 * associated with the packets.  The service class index of the
153 	 * packet is used as the index to ifcq_disc_slots[].
154 	 *
155 	 * ifcq_disc_slots[] therefore also acts as a lookup table which
156 	 * provides for the mapping between MBUF_SC values and the actual
157 	 * scheduler classes.
158 	 */
159 	struct ifclassq_disc_slot {
160 		u_int32_t       qid;
161 		void            *cl;
162 	} ifcq_disc_slots[IFCQ_SC_MAX]; /* for discipline use */
163 
164 	/* token bucket regulator */
165 	struct tb_regulator     ifcq_tbr;       /* TBR */
166 };
167 
168 /* ifcq_flags */
169 #define IFCQF_READY      0x01           /* ifclassq supports discipline */
170 #define IFCQF_ENABLED    0x02           /* ifclassq is in use */
171 #define IFCQF_TBR        0x04           /* Token Bucket Regulator is in use */
172 #define IFCQF_DESTROYED  0x08           /* ifclassq torndown */
173 
174 #define IFCQ_IS_READY(_ifcq)            ((_ifcq)->ifcq_flags & IFCQF_READY)
175 #define IFCQ_IS_ENABLED(_ifcq)          ((_ifcq)->ifcq_flags & IFCQF_ENABLED)
176 #define IFCQ_TBR_IS_ENABLED(_ifcq)      ((_ifcq)->ifcq_flags & IFCQF_TBR)
177 #define IFCQ_IS_DESTROYED(_ifcq)        ((_ifcq)->ifcq_flags & IFCQF_DESTROYED)
178 
179 /* classq enqueue return value */
180 /* packet has to be dropped */
181 #define CLASSQEQ_DROP           (-1)
182 /* packet successfully enqueued */
183 #define CLASSQEQ_SUCCESS        0
184 /* packet enqueued; give flow control feedback */
185 #define CLASSQEQ_SUCCESS_FC     1
186 /* packet needs to be dropped due to flowcontrol; give flow control feedback */
187 #define CLASSQEQ_DROP_FC        2
188 /* packet needs to be dropped due to suspension; give flow control feedback */
189 #define CLASSQEQ_DROP_SP        3
190 /* packet has been compressed with another one */
191 #define CLASSQEQ_COMPRESSED     4
192 
193 /* interface event argument for CLASSQRQ_EVENT */
194 typedef enum cqev {
195 	CLASSQ_EV_INIT = 0,
196 	CLASSQ_EV_LINK_BANDWIDTH = 1,   /* link bandwidth has changed */
197 	CLASSQ_EV_LINK_LATENCY = 2,     /* link latency has changed */
198 	CLASSQ_EV_LINK_MTU =    3,      /* link MTU has changed */
199 	CLASSQ_EV_LINK_UP =     4,      /* link is now up */
200 	CLASSQ_EV_LINK_DOWN =   5,      /* link is now down */
201 } cqev_t;
202 #endif /* BSD_KERNEL_PRIVATE */
203 
204 #define IF_CLASSQ_DEF                   0x0
205 #define IF_CLASSQ_LOW_LATENCY           0x1
206 #define IF_CLASSQ_L4S                   0x2
207 #define IF_DEFAULT_GRP                  0x4
208 
209 #define IF_CLASSQ_ALL_GRPS              UINT8_MAX
210 
211 #include <net/classq/classq.h>
212 #include <net/pktsched/pktsched_fq_codel.h>
213 
214 #ifdef __cplusplus
215 extern "C" {
216 #endif
217 struct if_ifclassq_stats {
218 	u_int32_t       ifqs_len;
219 	u_int32_t       ifqs_maxlen;
220 	struct pktcntr  ifqs_xmitcnt;
221 	struct pktcntr  ifqs_dropcnt;
222 	u_int32_t       ifqs_scheduler;
223 	struct fq_codel_classstats      ifqs_fq_codel_stats;
224 } __attribute__((aligned(8)));
225 
226 #ifdef __cplusplus
227 }
228 #endif
229 
230 #ifdef BSD_KERNEL_PRIVATE
231 /*
232  * For ifclassq lock
233  */
234 #define IFCQ_LOCK_ASSERT_HELD(_ifcq)                                    \
235 	LCK_MTX_ASSERT(&(_ifcq)->ifcq_lock, LCK_MTX_ASSERT_OWNED)
236 
237 #define IFCQ_LOCK_ASSERT_NOTHELD(_ifcq)                                 \
238 	LCK_MTX_ASSERT(&(_ifcq)->ifcq_lock, LCK_MTX_ASSERT_NOTOWNED)
239 
240 #define IFCQ_LOCK(_ifcq)                                                \
241 	lck_mtx_lock(&(_ifcq)->ifcq_lock)
242 
243 #define IFCQ_LOCK_SPIN(_ifcq)                                           \
244 	lck_mtx_lock_spin(&(_ifcq)->ifcq_lock)
245 
246 #define IFCQ_CONVERT_LOCK(_ifcq) do {                                   \
247 	IFCQ_LOCK_ASSERT_HELD(_ifcq);                                   \
248 	lck_mtx_convert_spin(&(_ifcq)->ifcq_lock);                      \
249 } while (0)
250 
251 #define IFCQ_UNLOCK(_ifcq)                                              \
252 	lck_mtx_unlock(&(_ifcq)->ifcq_lock)
253 
254 /*
255  * For ifclassq operations
256  */
257 #define IFCQ_TBR_DEQUEUE(_ifcq, _p, _idx) do {                      \
258 	ifclassq_tbr_dequeue(_ifcq, _p, _idx);                          \
259 } while (0)
260 
261 #define IFCQ_TBR_DEQUEUE_SC(_ifcq, _sc, _p, _idx) do {                        \
262 	ifclassq_tbr_dequeue_sc(_ifcq, _sc, _p, _idx);                        \
263 } while (0)
264 
265 #define IFCQ_LEN(_ifcq)         ((_ifcq)->ifcq_len)
266 #define IFCQ_QFULL(_ifcq)       (IFCQ_LEN(_ifcq) >= (_ifcq)->ifcq_maxlen)
267 #define IFCQ_IS_EMPTY(_ifcq)    (IFCQ_LEN(_ifcq) == 0)
268 #define IFCQ_INC_LEN(_ifcq)     (IFCQ_LEN(_ifcq)++)
269 #define IFCQ_DEC_LEN(_ifcq)     (IFCQ_LEN(_ifcq)--)
270 #define IFCQ_ADD_LEN(_ifcq, _len) (IFCQ_LEN(_ifcq) += (_len))
271 #define IFCQ_SUB_LEN(_ifcq, _len) (IFCQ_LEN(_ifcq) -= (_len))
272 #define IFCQ_MAXLEN(_ifcq)      ((_ifcq)->ifcq_maxlen)
273 #define IFCQ_SET_MAXLEN(_ifcq, _len) ((_ifcq)->ifcq_maxlen = (_len))
274 #define IFCQ_TARGET_QDELAY(_ifcq)       ((_ifcq)->ifcq_target_qdelay)
275 #define IFCQ_BYTES(_ifcq)       ((_ifcq)->ifcq_bytes)
276 #define IFCQ_INC_BYTES(_ifcq, _len)     \
277     ((_ifcq)->ifcq_bytes = (_ifcq)->ifcq_bytes + (_len))
278 #define IFCQ_DEC_BYTES(_ifcq, _len)     \
279     ((_ifcq)->ifcq_bytes = (_ifcq)->ifcq_bytes - (_len))
280 
281 #define IFCQ_XMIT_ADD(_ifcq, _pkt, _len) do {                           \
282 	PKTCNTR_ADD(&(_ifcq)->ifcq_xmitcnt, _pkt, _len);                \
283 } while (0)
284 
285 #define IFCQ_DROP_ADD(_ifcq, _pkt, _len) do {                           \
286 	PKTCNTR_ADD(&(_ifcq)->ifcq_dropcnt, _pkt, _len);                \
287 } while (0)
288 
289 #define IFCQ_PKT_DROP_LIMIT(_ifcq)      ((_ifcq)->ifcq_pkt_drop_limit)
290 
291 extern int ifclassq_setup(struct ifclassq *, struct ifnet *, uint32_t);
292 extern void ifclassq_teardown(struct ifclassq *);
293 extern int ifclassq_pktsched_setup(struct ifclassq *);
294 extern void ifclassq_set_maxlen(struct ifclassq *, u_int32_t);
295 extern u_int32_t ifclassq_get_maxlen(struct ifclassq *);
296 extern int ifclassq_get_len(struct ifclassq *, mbuf_svc_class_t,
297     u_int8_t, u_int32_t *, u_int32_t *);
298 extern errno_t ifclassq_enqueue(struct ifclassq *, classq_pkt_t *,
299     classq_pkt_t *, u_int32_t, u_int32_t, boolean_t *);
300 extern errno_t ifclassq_dequeue(struct ifclassq *, u_int32_t, u_int32_t,
301     classq_pkt_t *, classq_pkt_t *, u_int32_t *, u_int32_t *, u_int8_t);
302 extern errno_t ifclassq_dequeue_sc(struct ifclassq *, mbuf_svc_class_t,
303     u_int32_t, u_int32_t, classq_pkt_t *, classq_pkt_t *, u_int32_t *,
304     u_int32_t *, u_int8_t);
305 extern void *ifclassq_poll(struct ifclassq *, classq_pkt_type_t *);
306 extern void *ifclassq_poll_sc(struct ifclassq *, mbuf_svc_class_t,
307     classq_pkt_type_t *);
308 extern void ifclassq_update(struct ifclassq *, cqev_t);
309 extern int ifclassq_attach(struct ifclassq *, u_int32_t, void *);
310 extern void ifclassq_detach(struct ifclassq *);
311 extern int ifclassq_getqstats(struct ifclassq *, u_int8_t, u_int32_t,
312     void *, u_int32_t *);
313 extern const char *ifclassq_ev2str(cqev_t);
314 extern int ifclassq_tbr_set(struct ifclassq *, struct tb_profile *, boolean_t);
315 extern void ifclassq_tbr_dequeue(struct ifclassq *, classq_pkt_t *, u_int8_t);
316 extern void ifclassq_tbr_dequeue_sc(struct ifclassq *, mbuf_svc_class_t,
317     classq_pkt_t *, u_int8_t);
318 extern void ifclassq_calc_target_qdelay(struct ifnet *ifp,
319     uint64_t *if_target_qdelay, uint32_t flags);
320 extern void ifclassq_calc_update_interval(uint64_t *update_interval,
321     uint32_t flags);
322 extern void ifclassq_set_packet_metadata(struct ifclassq *ifq,
323     struct ifnet *ifp, classq_pkt_t *p);
324 extern void ifclassq_reap_caches(boolean_t);
325 extern struct ifclassq *ifclassq_alloc(void);
326 extern void ifclassq_retain(struct ifclassq *);
327 extern void ifclassq_release(struct ifclassq **);
328 extern int ifclassq_setup_group(struct ifclassq *ifcq, uint8_t grp_idx,
329     uint8_t flags);
330 extern void ifclassq_set_grp_combined(struct ifclassq *ifcq, uint8_t grp_idx);
331 extern void ifclassq_set_grp_separated(struct ifclassq *ifcq, uint8_t grp_idx);
332 
333 #endif /* BSD_KERNEL_PRIVATE */
334 #endif /* PRIVATE */
335 #endif /* _NET_CLASSQ_IF_CLASSQ_H_ */
336