xref: /xnu-12377.61.12/bsd/net/classq/if_classq.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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 extern uint32_t ifclassq_congestion_feedback;
107 #endif /* DEBUG || DEVELOPMENT */
108 
109 typedef struct ifcq_sysctl_oid {
110 	struct sysctl_oid_list  ifcq_oid_list;   /* oid & properties */
111 	struct sysctl_oid       ifcq_oid;        /* sysctl oid storage */
112 	char                    ifcq_name[32];   /* name */
113 } ifcq_oid_t;
114 
115 /*
116  * Structure defining a queue for a network interface.
117  */
118 struct ifclassq {
119 	decl_lck_mtx_data(, ifcq_lock);
120 
121 	os_refcnt_t     ifcq_refcnt;
122 	struct ifnet    *ifcq_ifp;      /* back pointer to interface */
123 	u_int32_t       ifcq_len;       /* packet count */
124 	u_int32_t       ifcq_maxlen;
125 	struct pktcntr  ifcq_xmitcnt;
126 	struct pktcntr  ifcq_dropcnt;
127 
128 	u_int32_t       ifcq_type;      /* scheduler type */
129 	u_int32_t       ifcq_flags;     /* flags */
130 	u_int32_t       ifcq_sflags;    /* scheduler flags */
131 	u_int32_t       ifcq_target_qdelay; /* target queue delay */
132 	u_int32_t       ifcq_bytes;     /* bytes count */
133 	u_int32_t       ifcq_pkt_drop_limit;
134 	void            *ifcq_disc;     /* for scheduler-specific use */
135 	struct pktsched_ops  *ifcq_ops;
136 	/*
137 	 * ifcq_disc_slots[] represents the leaf classes configured for the
138 	 * corresponding discpline/scheduler, ordered by their corresponding
139 	 * service class index.  Each slot holds the queue ID used to identify
140 	 * the class instance, as well as the class instance pointer itself.
141 	 * The latter is used during enqueue and dequeue in order to avoid the
142 	 * costs associated with looking up the class pointer based on the
143 	 * queue ID.  The queue ID is used when querying the statistics from
144 	 * user space.
145 	 *
146 	 * Avoiding the use of queue ID during enqueue and dequeue is made
147 	 * possible by virtue of knowing the particular mbuf service class
148 	 * associated with the packets.  The service class index of the
149 	 * packet is used as the index to ifcq_disc_slots[].
150 	 *
151 	 * ifcq_disc_slots[] therefore also acts as a lookup table which
152 	 * provides for the mapping between MBUF_SC values and the actual
153 	 * scheduler classes.
154 	 */
155 	struct ifclassq_disc_slot {
156 		u_int32_t       qid;
157 		void            *cl;
158 	} ifcq_disc_slots[IFCQ_SC_MAX]; /* for discipline use */
159 
160 	/* token bucket regulator */
161 	struct tb_regulator     ifcq_tbr;       /* TBR */
162 	ifcq_oid_t              ifcq_oid;
163 };
164 
165 /* ifcq_flags */
166 #define IFCQF_READY      0x01           /* ifclassq supports discipline */
167 #define IFCQF_ENABLED    0x02           /* ifclassq is in use */
168 #define IFCQF_TBR        0x04           /* Token Bucket Regulator is in use */
169 #define IFCQF_DESTROYED  0x08           /* ifclassq torndown */
170 #define IFCQF_LOCKLESS   0x10           /* lockless */
171 
172 #define IFCQ_IS_READY(_ifcq)            ((_ifcq)->ifcq_flags & IFCQF_READY)
173 #define IFCQ_IS_ENABLED(_ifcq)          ((_ifcq)->ifcq_flags & IFCQF_ENABLED)
174 #define IFCQ_TBR_IS_ENABLED(_ifcq)      ((_ifcq)->ifcq_flags & IFCQF_TBR)
175 #define IFCQ_IS_DESTROYED(_ifcq)        ((_ifcq)->ifcq_flags & IFCQF_DESTROYED)
176 
177 /* classq enqueue return value */
178 /* packet has to be dropped */
179 #define CLASSQEQ_DROP           (-1)
180 /* packet successfully enqueued */
181 #define CLASSQEQ_SUCCESS        0
182 /* packet enqueued; give flow control feedback */
183 #define CLASSQEQ_SUCCESS_FC     1
184 /* packet needs to be dropped due to flowcontrol; give flow control feedback */
185 #define CLASSQEQ_DROP_FC        2
186 /* packet needs to be dropped due to suspension; give flow control feedback */
187 #define CLASSQEQ_DROP_SP        3
188 /* packet has been compressed with another one */
189 #define CLASSQEQ_COMPRESSED     4
190 
191 #define CLASSQEQ_CONGESTED      5
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 	uint64_t        ifqs_doorbells;
221 	struct pktcntr  ifqs_xmitcnt;
222 	struct pktcntr  ifqs_dropcnt;
223 	u_int32_t       ifqs_scheduler;
224 	union {
225 		struct fq_codel_classstats      ifqs_fq_codel_stats;
226 	};
227 } __attribute__((aligned(8)));
228 
229 #ifdef __cplusplus
230 }
231 #endif
232 
233 #ifdef BSD_KERNEL_PRIVATE
234 /*
235  * For ifclassq lock
236  */
237 #define IFCQ_LOCK_ASSERT_HELD(_ifcq)                                    \
238 	LCK_MTX_ASSERT(&(_ifcq)->ifcq_lock, LCK_MTX_ASSERT_OWNED)
239 
240 #define IFCQ_LOCK_ASSERT_NOTHELD(_ifcq)                                 \
241 	LCK_MTX_ASSERT(&(_ifcq)->ifcq_lock, LCK_MTX_ASSERT_NOTOWNED)
242 
243 #define IFCQ_LOCK(_ifcq)                                                \
244 	lck_mtx_lock(&(_ifcq)->ifcq_lock)
245 
246 #define IFCQ_LOCK_SPIN(_ifcq)                                           \
247 	lck_mtx_lock_spin(&(_ifcq)->ifcq_lock)
248 
249 #define IFCQ_CONVERT_LOCK(_ifcq) do {                                   \
250 	IFCQ_LOCK_ASSERT_HELD(_ifcq);                                   \
251 	lck_mtx_convert_spin(&(_ifcq)->ifcq_lock);                      \
252 } while (0)
253 
254 #define IFCQ_UNLOCK(_ifcq)                                              \
255 	lck_mtx_unlock(&(_ifcq)->ifcq_lock)
256 
257 /*
258  * For ifclassq operations
259  */
260 #define IFCQ_TBR_DEQUEUE(_ifcq, _p, _idx) do {                      \
261 	ifclassq_tbr_dequeue(_ifcq, _p, _idx);                          \
262 } while (0)
263 
264 #define IFCQ_TBR_DEQUEUE_SC(_ifcq, _sc, _p, _idx) do {                        \
265 	ifclassq_tbr_dequeue_sc(_ifcq, _sc, _p, _idx);                        \
266 } while (0)
267 
268 #define IFCQ_LEN(_ifcq)         ((_ifcq)->ifcq_len)
269 #define IFCQ_QFULL(_ifcq)       (IFCQ_LEN(_ifcq) >= (_ifcq)->ifcq_maxlen)
270 #define IFCQ_IS_EMPTY(_ifcq)    (IFCQ_LEN(_ifcq) == 0)
271 #define IFCQ_INC_LEN(_ifcq)     (IFCQ_LEN(_ifcq)++)
272 #define IFCQ_DEC_LEN(_ifcq)     (IFCQ_LEN(_ifcq)--)
273 #define IFCQ_ADD_LEN(_ifcq, _len) (IFCQ_LEN(_ifcq) += (_len))
274 #define IFCQ_SUB_LEN(_ifcq, _len) (IFCQ_LEN(_ifcq) -= (_len))
275 #define IFCQ_MAXLEN(_ifcq)      ((_ifcq)->ifcq_maxlen)
276 #define IFCQ_SET_MAXLEN(_ifcq, _len) ((_ifcq)->ifcq_maxlen = (_len))
277 #define IFCQ_TARGET_QDELAY(_ifcq)       ((_ifcq)->ifcq_target_qdelay)
278 #define IFCQ_BYTES(_ifcq)       ((_ifcq)->ifcq_bytes)
279 #define IFCQ_INC_BYTES(_ifcq, _len)     \
280     ((_ifcq)->ifcq_bytes = (_ifcq)->ifcq_bytes + (_len))
281 #define IFCQ_DEC_BYTES(_ifcq, _len)     \
282     ((_ifcq)->ifcq_bytes = (_ifcq)->ifcq_bytes - (_len))
283 
284 #define IFCQ_XMIT_ADD(_ifcq, _pkt, _len) do {                           \
285 	PKTCNTR_ADD(&(_ifcq)->ifcq_xmitcnt, _pkt, _len);                \
286 } while (0)
287 
288 #define IFCQ_DROP_ADD(_ifcq, _pkt, _len) do {                           \
289 	PKTCNTR_ADD(&(_ifcq)->ifcq_dropcnt, _pkt, _len);                \
290 } while (0)
291 
292 #define IFCQ_PKT_DROP_LIMIT(_ifcq)      ((_ifcq)->ifcq_pkt_drop_limit)
293 
294 extern int ifclassq_setup(struct ifclassq *, struct ifnet *, uint32_t);
295 extern int ifclassq_change(struct ifclassq *ifq, uint32_t model);
296 extern void ifclassq_teardown(struct ifclassq *);
297 extern int ifclassq_pktsched_setup(struct ifclassq *);
298 extern void ifclassq_set_maxlen(struct ifclassq *, u_int32_t);
299 extern u_int32_t ifclassq_get_maxlen(struct ifclassq *);
300 extern int ifclassq_get_len(struct ifclassq *, mbuf_svc_class_t,
301     u_int8_t, u_int32_t *, u_int32_t *);
302 extern errno_t ifclassq_enqueue(struct ifclassq *, classq_pkt_t *,
303     classq_pkt_t *, u_int32_t, u_int32_t, boolean_t *);
304 extern errno_t ifclassq_dequeue(struct ifclassq *, mbuf_svc_class_t,
305     u_int32_t, u_int32_t, classq_pkt_t *, classq_pkt_t *, u_int32_t *,
306     u_int32_t *, u_int8_t);
307 extern void ifclassq_update(struct ifclassq *, cqev_t, bool);
308 extern int ifclassq_attach(struct ifclassq *, u_int32_t, void *);
309 extern void ifclassq_detach(struct ifclassq *);
310 extern int ifclassq_getqstats(struct ifclassq *, u_int8_t, u_int32_t,
311     void *, u_int32_t *);
312 extern const char *__null_terminated ifclassq_ev2str(cqev_t);
313 extern int ifclassq_tbr_set(struct ifclassq *, struct tb_profile *, boolean_t);
314 extern void ifclassq_tbr_get(struct ifclassq *, u_int32_t *, u_int64_t *, u_int64_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_set_packet_metadata(struct ifclassq *ifq,
319     struct ifnet *ifp, classq_pkt_t *p);
320 extern struct ifclassq *ifclassq_alloc(void);
321 extern void ifclassq_retain(struct ifclassq *);
322 extern void ifclassq_release(struct ifclassq **);
323 extern int ifclassq_setup_group(struct ifclassq *ifcq, uint8_t grp_idx,
324     uint8_t flags);
325 extern int ifclassq_request(struct ifclassq *, enum cqrq, void *, bool);
326 
327 #endif /* BSD_KERNEL_PRIVATE */
328 #endif /* PRIVATE */
329 #endif /* _NET_CLASSQ_IF_CLASSQ_H_ */
330