1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa
5 * All rights reserved
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 * The API to write a packet scheduling algorithm for dummynet.
31 *
32 * $FreeBSD$
33 */
34
35#ifndef _DN_SCHED_H
36#define _DN_SCHED_H
37
38#include <sys/ck.h>
39
40#define	DN_MULTIQUEUE	0x01
41/*
42 * Descriptor for a scheduling algorithm.
43 * Contains all function pointers for a given scheduler
44 * This is typically created when a module is loaded, and stored
45 * in a global list of schedulers.
46 */
47struct dn_alg {
48	uint32_t type;           /* the scheduler type */
49	const char *name;   /* scheduler name */
50	uint32_t flags;	/* DN_MULTIQUEUE if supports multiple queues */
51
52	/*
53	 * The following define the size of 3 optional data structures
54	 * that may need to be allocated at runtime, and are appended
55	 * to each of the base data structures: scheduler, sched.inst,
56	 * and queue. We don't have a per-flowset structure.
57	 */
58	/*    + parameters attached to the template, e.g.
59	 *	default queue sizes, weights, quantum size, and so on;
60	 */
61	size_t schk_datalen;
62
63	/*    + per-instance parameters, such as timestamps,
64	 *	containers for queues, etc;
65	 */
66	size_t si_datalen;
67
68	size_t q_datalen;	/* per-queue parameters (e.g. S,F) */
69
70	/*
71	 * Methods implemented by the scheduler:
72	 * enqueue	enqueue packet 'm' on scheduler 's', queue 'q'.
73	 *	q is NULL for !MULTIQUEUE.
74	 *	Return 0 on success, 1 on drop (packet consumed anyways).
75	 *	Note that q should be interpreted only as a hint
76	 *	on the flow that the mbuf belongs to: while a
77	 *	scheduler will normally enqueue m into q, it is ok
78	 *	to leave q alone and put the mbuf elsewhere.
79	 *	This function is called in two cases:
80	 *	 - when a new packet arrives to the scheduler;
81	 *	 - when a scheduler is reconfigured. In this case the
82	 *	   call is issued by the new_queue callback, with a
83	 *	   non empty queue (q) and m pointing to the first
84	 *	   mbuf in the queue. For this reason, the function
85	 *	   should internally check for (m != q->mq.head)
86	 *	   before calling dn_enqueue().
87	 *
88	 * dequeue	Called when scheduler instance 's' can
89	 *	dequeue a packet. Return NULL if none are available.
90	 *	XXX what about non work-conserving ?
91	 *
92	 * config	called on 'sched X config ...', normally writes
93	 *	in the area of size sch_arg
94	 *
95	 * destroy	called on 'sched delete', frees everything
96	 *	in sch_arg (other parts are handled by more specific
97	 *	functions)
98	 *
99	 * new_sched    called when a new instance is created, e.g.
100	 *	to create the local queue for !MULTIQUEUE, set V or
101	 *	copy parameters for WFQ, and so on.
102	 *
103	 * free_sched	called when deleting an instance, cleans
104	 *	extra data in the per-instance area.
105	 *
106	 * new_fsk	called when a flowset is linked to a scheduler,
107	 *	e.g. to validate parameters such as weights etc.
108	 * free_fsk	when a flowset is unlinked from a scheduler.
109	 *	(probably unnecessary)
110	 *
111	 * new_queue	called to set the per-queue parameters,
112	 *	e.g. S and F, adjust sum of weights in the parent, etc.
113	 *
114	 *	The new_queue callback is normally called from when
115	 *	creating a new queue. In some cases (such as a
116	 *	scheduler change or reconfiguration) it can be called
117	 *	with a non empty queue. In this case, the queue
118	 *	In case of non empty queue, the new_queue callback could
119	 *	need to call the enqueue function. In this case,
120	 *	the callback should eventually call enqueue() passing
121	 *	as m the first element in the queue.
122	 *
123	 * free_queue	actions related to a queue removal, e.g. undo
124	 *	all the above. If the queue has data in it, also remove
125	 *	from the scheduler. This can e.g. happen during a reconfigure.
126	 */
127	int (*enqueue)(struct dn_sch_inst *, struct dn_queue *,
128		struct mbuf *);
129	struct mbuf * (*dequeue)(struct dn_sch_inst *);
130
131	int (*config)(struct dn_schk *);
132	int (*destroy)(struct dn_schk*);
133	int (*new_sched)(struct dn_sch_inst *);
134	int (*free_sched)(struct dn_sch_inst *);
135	int (*new_fsk)(struct dn_fsk *f);
136	int (*free_fsk)(struct dn_fsk *f);
137	int (*new_queue)(struct dn_queue *q);
138	int (*free_queue)(struct dn_queue *q);
139#ifdef NEW_AQM
140	/* Getting scheduler extra parameters */
141	int (*getconfig)(struct dn_schk *, struct dn_extra_parms *);
142#endif
143
144	/* run-time fields */
145	int ref_count;      /* XXX number of instances in the system */
146	CK_LIST_ENTRY(dn_alg) next; /* Next scheduler in the list */
147};
148
149/* MSVC does not support initializers so we need this ugly macro */
150#ifdef _WIN32
151#define _SI(fld)
152#else
153#define _SI(fld)	fld
154#endif
155
156/*
157 * Additionally, dummynet exports some functions and macros
158 * to be used by schedulers:
159 */
160
161void dn_free_pkts(struct mbuf *mnext);
162int dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);
163/* bound a variable between min and max */
164int ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);
165
166/*
167 * Extract the head of a queue, update stats. Must be the very last
168 * thing done on a dequeue as the queue itself may go away.
169 */
170static __inline struct mbuf*
171dn_dequeue(struct dn_queue *q)
172{
173	struct mbuf *m = q->mq.head;
174	if (m == NULL)
175		return NULL;
176#ifdef NEW_AQM
177	/* Call AQM dequeue function  */
178	if (q->fs->aqmfp && q->fs->aqmfp->dequeue )
179		return q->fs->aqmfp->dequeue(q);
180#endif
181	q->mq.head = m->m_nextpkt;
182	q->mq.count--;
183
184	/* Update stats for the queue */
185	q->ni.length--;
186	q->ni.len_bytes -= m->m_pkthdr.len;
187	if (q->_si) {
188		q->_si->ni.length--;
189		q->_si->ni.len_bytes -= m->m_pkthdr.len;
190	}
191	if (q->ni.length == 0) /* queue is now idle */
192		q->q_time = V_dn_cfg.curr_time;
193	return m;
194}
195
196int dn_sched_modevent(module_t mod, int cmd, void *arg);
197
198#define DECLARE_DNSCHED_MODULE(name, dnsched)			\
199	static moduledata_t name##_mod = {			\
200		#name, dn_sched_modevent, dnsched		\
201	};							\
202	DECLARE_MODULE(name, name##_mod, 			\
203		SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); 		\
204        MODULE_DEPEND(name, dummynet, 3, 3, 3)
205#endif /* _DN_SCHED_H */
206