Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/ipfw/dn_sched_rr.c
39482 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2010 Riccardo Panicucci, 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
*/
31
32
#ifdef _KERNEL
33
#include <sys/malloc.h>
34
#include <sys/socket.h>
35
#include <sys/socketvar.h>
36
#include <sys/kernel.h>
37
#include <sys/lock.h>
38
#include <sys/mbuf.h>
39
#include <sys/module.h>
40
#include <sys/rwlock.h>
41
#include <net/if.h> /* IFNAMSIZ */
42
#include <netinet/in.h>
43
#include <netinet/ip_var.h> /* ipfw_rule_ref */
44
#include <netinet/ip_fw.h> /* flow_id */
45
#include <netinet/ip_dummynet.h>
46
#include <netpfil/ipfw/ip_fw_private.h>
47
#include <netpfil/ipfw/dn_heap.h>
48
#include <netpfil/ipfw/ip_dn_private.h>
49
#ifdef NEW_AQM
50
#include <netpfil/ipfw/dn_aqm.h>
51
#endif
52
#include <netpfil/ipfw/dn_sched.h>
53
#else
54
#include <dn_test.h>
55
#endif
56
57
#define DN_SCHED_RR 3 // XXX Where?
58
59
struct rr_queue {
60
struct dn_queue q; /* Standard queue */
61
int status; /* 1: queue is in the list */
62
uint32_t credit; /* max bytes we can transmit */
63
uint32_t quantum; /* quantum * weight */
64
struct rr_queue *qnext; /* */
65
};
66
67
/* struct rr_schk contains global config parameters
68
* and is right after dn_schk
69
*/
70
struct rr_schk {
71
uint32_t min_q; /* Min quantum */
72
uint32_t max_q; /* Max quantum */
73
uint32_t q_bytes; /* default quantum in bytes */
74
};
75
76
/* per-instance round robin list, right after dn_sch_inst */
77
struct rr_si {
78
struct rr_queue *head, *tail; /* Pointer to current queue */
79
};
80
81
/* Append a queue to the rr list */
82
static inline void
83
rr_append(struct rr_queue *q, struct rr_si *si)
84
{
85
q->status = 1; /* mark as in-rr_list */
86
q->credit = q->quantum; /* initialize credit */
87
88
/* append to the tail */
89
if (si->head == NULL)
90
si->head = q;
91
else
92
si->tail->qnext = q;
93
si->tail = q; /* advance the tail pointer */
94
q->qnext = si->head; /* make it circular */
95
}
96
97
/* Remove the head queue from circular list. */
98
static inline void
99
rr_remove_head(struct rr_si *si)
100
{
101
if (si->head == NULL)
102
return; /* empty queue */
103
si->head->status = 0;
104
105
if (si->head == si->tail) {
106
si->head = si->tail = NULL;
107
return;
108
}
109
110
si->head = si->head->qnext;
111
si->tail->qnext = si->head;
112
}
113
114
/* Remove a queue from circular list.
115
* XXX see if ti can be merge with remove_queue()
116
*/
117
static inline void
118
remove_queue_q(struct rr_queue *q, struct rr_si *si)
119
{
120
struct rr_queue *prev;
121
122
if (q->status != 1)
123
return;
124
if (q == si->head) {
125
rr_remove_head(si);
126
return;
127
}
128
129
for (prev = si->head; prev; prev = prev->qnext) {
130
if (prev->qnext != q)
131
continue;
132
prev->qnext = q->qnext;
133
if (q == si->tail)
134
si->tail = prev;
135
q->status = 0;
136
break;
137
}
138
}
139
140
static inline void
141
next_pointer(struct rr_si *si)
142
{
143
if (si->head == NULL)
144
return; /* empty queue */
145
146
si->head = si->head->qnext;
147
si->tail = si->tail->qnext;
148
}
149
150
static int
151
rr_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)
152
{
153
struct rr_si *si;
154
struct rr_queue *rrq;
155
156
if (m != q->mq.head) {
157
if (dn_enqueue(q, m, 0)) /* packet was dropped */
158
return 1;
159
if (m != q->mq.head)
160
return 0;
161
}
162
163
/* If reach this point, queue q was idle */
164
si = (struct rr_si *)(_si + 1);
165
rrq = (struct rr_queue *)q;
166
167
if (rrq->status == 1) /* Queue is already in the queue list */
168
return 0;
169
170
/* Insert the queue in the queue list */
171
rr_append(rrq, si);
172
173
return 0;
174
}
175
176
static struct mbuf *
177
rr_dequeue(struct dn_sch_inst *_si)
178
{
179
/* Access scheduler instance private data */
180
struct rr_si *si = (struct rr_si *)(_si + 1);
181
struct rr_queue *rrq;
182
uint64_t len;
183
184
while ( (rrq = si->head) ) {
185
struct mbuf *m = rrq->q.mq.head;
186
if ( m == NULL) {
187
/* empty queue, remove from list */
188
rr_remove_head(si);
189
continue;
190
}
191
len = m->m_pkthdr.len;
192
193
if (len > rrq->credit) {
194
/* Packet too big */
195
rrq->credit += rrq->quantum;
196
/* Try next queue */
197
next_pointer(si);
198
} else {
199
rrq->credit -= len;
200
return dn_dequeue(&rrq->q);
201
}
202
}
203
204
/* no packet to dequeue*/
205
return NULL;
206
}
207
208
static int
209
rr_config(struct dn_schk *_schk)
210
{
211
struct rr_schk *schk = (struct rr_schk *)(_schk + 1);
212
ND("called");
213
214
/* use reasonable quantums (64..2k bytes, default 1500) */
215
schk->min_q = 64;
216
schk->max_q = 2048;
217
schk->q_bytes = 1500; /* quantum */
218
219
return 0;
220
}
221
222
static int
223
rr_new_sched(struct dn_sch_inst *_si)
224
{
225
struct rr_si *si = (struct rr_si *)(_si + 1);
226
227
ND("called");
228
si->head = si->tail = NULL;
229
230
return 0;
231
}
232
233
static int
234
rr_free_sched(struct dn_sch_inst *_si)
235
{
236
(void)_si;
237
ND("called");
238
/* Nothing to do? */
239
return 0;
240
}
241
242
static int
243
rr_new_fsk(struct dn_fsk *fs)
244
{
245
struct rr_schk *schk = (struct rr_schk *)(fs->sched + 1);
246
/* par[0] is the weight, par[1] is the quantum step */
247
/* make sure the product fits an uint32_t */
248
ipdn_bound_var(&fs->fs.par[0], 1,
249
1, 65536, "RR weight");
250
ipdn_bound_var(&fs->fs.par[1], schk->q_bytes,
251
schk->min_q, schk->max_q, "RR quantum");
252
return 0;
253
}
254
255
static int
256
rr_new_queue(struct dn_queue *_q)
257
{
258
struct rr_queue *q = (struct rr_queue *)_q;
259
uint64_t quantum;
260
261
_q->ni.oid.subtype = DN_SCHED_RR;
262
263
quantum = (uint64_t)_q->fs->fs.par[0] * _q->fs->fs.par[1];
264
if (quantum >= (1ULL<< 32)) {
265
D("quantum too large, truncating to 4G - 1");
266
quantum = (1ULL<< 32) - 1;
267
}
268
q->quantum = quantum;
269
ND("called, q->quantum %d", q->quantum);
270
q->credit = q->quantum;
271
q->status = 0;
272
273
if (_q->mq.head != NULL) {
274
/* Queue NOT empty, insert in the queue list */
275
rr_append(q, (struct rr_si *)(_q->_si + 1));
276
}
277
return 0;
278
}
279
280
static int
281
rr_free_queue(struct dn_queue *_q)
282
{
283
struct rr_queue *q = (struct rr_queue *)_q;
284
285
ND("called");
286
if (q->status == 1) {
287
struct rr_si *si = (struct rr_si *)(_q->_si + 1);
288
remove_queue_q(q, si);
289
}
290
return 0;
291
}
292
293
/*
294
* RR scheduler descriptor
295
* contains the type of the scheduler, the name, the size of the
296
* structures and function pointers.
297
*/
298
static struct dn_alg rr_desc = {
299
_SI( .type = ) DN_SCHED_RR,
300
_SI( .name = ) "RR",
301
_SI( .flags = ) DN_MULTIQUEUE,
302
303
_SI( .schk_datalen = ) sizeof(struct rr_schk),
304
_SI( .si_datalen = ) sizeof(struct rr_si),
305
_SI( .q_datalen = ) sizeof(struct rr_queue) - sizeof(struct dn_queue),
306
307
_SI( .enqueue = ) rr_enqueue,
308
_SI( .dequeue = ) rr_dequeue,
309
310
_SI( .config = ) rr_config,
311
_SI( .destroy = ) NULL,
312
_SI( .new_sched = ) rr_new_sched,
313
_SI( .free_sched = ) rr_free_sched,
314
_SI( .new_fsk = ) rr_new_fsk,
315
_SI( .free_fsk = ) NULL,
316
_SI( .new_queue = ) rr_new_queue,
317
_SI( .free_queue = ) rr_free_queue,
318
#ifdef NEW_AQM
319
_SI( .getconfig = ) NULL,
320
#endif
321
};
322
323
DECLARE_DNSCHED_MODULE(dn_rr, &rr_desc);
324
325