Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/ipfw/dn_sched_prio.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
#ifdef _KERNEL
32
#include <sys/malloc.h>
33
#include <sys/socket.h>
34
#include <sys/socketvar.h>
35
#include <sys/kernel.h>
36
#include <sys/lock.h>
37
#include <sys/mbuf.h>
38
#include <sys/module.h>
39
#include <sys/rwlock.h>
40
#include <net/if.h> /* IFNAMSIZ */
41
#include <netinet/in.h>
42
#include <netinet/ip_var.h> /* ipfw_rule_ref */
43
#include <netinet/ip_fw.h> /* flow_id */
44
#include <netinet/ip_dummynet.h>
45
#include <netpfil/ipfw/ip_fw_private.h>
46
#include <netpfil/ipfw/dn_heap.h>
47
#include <netpfil/ipfw/ip_dn_private.h>
48
#ifdef NEW_AQM
49
#include <netpfil/ipfw/dn_aqm.h>
50
#endif
51
#include <netpfil/ipfw/dn_sched.h>
52
#else
53
#include <dn_test.h>
54
#endif
55
56
#define DN_SCHED_PRIO 5 //XXX
57
58
#if !defined(_KERNEL) || !defined(__linux__)
59
#define test_bit(ix, pData) ((*pData) & (1<<(ix)))
60
#define __set_bit(ix, pData) (*pData) |= (1<<(ix))
61
#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
62
#endif
63
64
#ifdef __MIPSEL__
65
#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
66
#endif
67
68
/* Size of the array of queues pointers. */
69
#define BITMAP_T unsigned long
70
#define MAXPRIO (sizeof(BITMAP_T) * 8)
71
72
/*
73
* The scheduler instance contains an array of pointers to queues,
74
* one for each priority, and a bitmap listing backlogged queues.
75
*/
76
struct prio_si {
77
BITMAP_T bitmap; /* array bitmap */
78
struct dn_queue *q_array[MAXPRIO]; /* Array of queues pointers */
79
};
80
81
/*
82
* If a queue with the same priority is already backlogged, use
83
* that one instead of the queue passed as argument.
84
*/
85
static int
86
prio_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)
87
{
88
struct prio_si *si = (struct prio_si *)(_si + 1);
89
int prio = q->fs->fs.par[0];
90
91
if (test_bit(prio, &si->bitmap) == 0) {
92
/* No queue with this priority, insert */
93
__set_bit(prio, &si->bitmap);
94
si->q_array[prio] = q;
95
} else { /* use the existing queue */
96
q = si->q_array[prio];
97
}
98
if (dn_enqueue(q, m, 0))
99
return 1;
100
return 0;
101
}
102
103
/*
104
* Packets are dequeued only from the highest priority queue.
105
* The function ffs() return the lowest bit in the bitmap that rapresent
106
* the array index (-1) which contains the pointer to the highest priority
107
* queue.
108
* After the dequeue, if this queue become empty, it is index is removed
109
* from the bitmap.
110
* Scheduler is idle if the bitmap is empty
111
*
112
* NOTE: highest priority is 0, lowest is sched->max_prio_q
113
*/
114
static struct mbuf *
115
prio_dequeue(struct dn_sch_inst *_si)
116
{
117
struct prio_si *si = (struct prio_si *)(_si + 1);
118
struct mbuf *m;
119
struct dn_queue *q;
120
int prio;
121
122
if (si->bitmap == 0) /* scheduler idle */
123
return NULL;
124
125
prio = ffs(si->bitmap) - 1;
126
127
/* Take the highest priority queue in the scheduler */
128
q = si->q_array[prio];
129
// assert(q)
130
131
m = dn_dequeue(q);
132
if (q->mq.head == NULL) {
133
/* Queue is now empty, remove from scheduler
134
* and mark it
135
*/
136
si->q_array[prio] = NULL;
137
__clear_bit(prio, &si->bitmap);
138
}
139
return m;
140
}
141
142
static int
143
prio_new_sched(struct dn_sch_inst *_si)
144
{
145
struct prio_si *si = (struct prio_si *)(_si + 1);
146
147
bzero(si->q_array, sizeof(si->q_array));
148
si->bitmap = 0;
149
150
return 0;
151
}
152
153
static int
154
prio_new_fsk(struct dn_fsk *fs)
155
{
156
/* Check if the prioritiy is between 0 and MAXPRIO-1 */
157
ipdn_bound_var(&fs->fs.par[0], 0, 0, MAXPRIO - 1, "PRIO priority");
158
return 0;
159
}
160
161
static int
162
prio_new_queue(struct dn_queue *q)
163
{
164
struct prio_si *si = (struct prio_si *)(q->_si + 1);
165
int prio = q->fs->fs.par[0];
166
struct dn_queue *oldq;
167
168
q->ni.oid.subtype = DN_SCHED_PRIO;
169
170
if (q->mq.head == NULL)
171
return 0;
172
173
/* Queue already full, must insert in the scheduler or append
174
* mbufs to existing queue. This partly duplicates prio_enqueue
175
*/
176
if (test_bit(prio, &si->bitmap) == 0) {
177
/* No queue with this priority, insert */
178
__set_bit(prio, &si->bitmap);
179
si->q_array[prio] = q;
180
} else if ( (oldq = si->q_array[prio]) != q) {
181
/* must append to the existing queue.
182
* can simply append q->mq.head to q2->...
183
* and add the counters to those of q2
184
*/
185
oldq->mq.tail->m_nextpkt = q->mq.head;
186
oldq->mq.tail = q->mq.tail;
187
oldq->ni.length += q->ni.length;
188
q->ni.length = 0;
189
oldq->ni.len_bytes += q->ni.len_bytes;
190
q->ni.len_bytes = 0;
191
q->mq.tail = q->mq.head = NULL;
192
}
193
return 0;
194
}
195
196
static int
197
prio_free_queue(struct dn_queue *q)
198
{
199
int prio = q->fs->fs.par[0];
200
struct prio_si *si = (struct prio_si *)(q->_si + 1);
201
202
if (si->q_array[prio] == q) {
203
si->q_array[prio] = NULL;
204
__clear_bit(prio, &si->bitmap);
205
}
206
return 0;
207
}
208
209
static struct dn_alg prio_desc = {
210
_SI( .type = ) DN_SCHED_PRIO,
211
_SI( .name = ) "PRIO",
212
_SI( .flags = ) DN_MULTIQUEUE,
213
214
/* we need extra space in the si and the queue */
215
_SI( .schk_datalen = ) 0,
216
_SI( .si_datalen = ) sizeof(struct prio_si),
217
_SI( .q_datalen = ) 0,
218
219
_SI( .enqueue = ) prio_enqueue,
220
_SI( .dequeue = ) prio_dequeue,
221
222
_SI( .config = ) NULL,
223
_SI( .destroy = ) NULL,
224
_SI( .new_sched = ) prio_new_sched,
225
_SI( .free_sched = ) NULL,
226
227
_SI( .new_fsk = ) prio_new_fsk,
228
_SI( .free_fsk = ) NULL,
229
230
_SI( .new_queue = ) prio_new_queue,
231
_SI( .free_queue = ) prio_free_queue,
232
#ifdef NEW_AQM
233
_SI( .getconfig = ) NULL,
234
#endif
235
};
236
237
DECLARE_DNSCHED_MODULE(dn_prio, &prio_desc);
238
239