1 /* $NetBSD: altq_fifoq.c,v 1.15 2006/11/16 01:32:37 christos Exp $ */
2 /* $KAME: altq_fifoq.c,v 1.12 2003/07/10 12:07:48 kjc Exp $ */
5 * Copyright (C) 1997-2002
6 * Sony Computer Science Laboratories Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: altq_fifoq.c,v 1.15 2006/11/16 01:32:37 christos Exp $");
37 #ifdef ALTQ_FIFOQ /* fifoq is enabled by ALTQ_FIFOQ option in opt_altq.h */
40 * FIFOQ is an altq sample implementation. There will be little
41 * need to use FIFOQ as an alternative queueing scheme.
42 * But this code is provided as a template for those who want to
43 * write their own queueing schemes.
46 #include <sys/param.h>
47 #include <sys/malloc.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/systm.h>
53 #include <sys/errno.h>
54 #include <sys/kernel.h>
55 #include <sys/kauth.h>
58 #include <net/if_types.h>
59 #include <netinet/in.h>
61 #include <altq/altq.h>
62 #include <altq/altq_conf.h>
63 #include <altq/altq_fifoq.h>
67 #define FIFOQ_STATS /* collect statistics */
69 /* fifoq_list keeps all fifoq_state_t's allocated. */
70 static fifoq_state_t
*fifoq_list
= NULL
;
72 /* internal function prototypes */
73 static int fifoq_enqueue(struct ifaltq
*, struct mbuf
*,
74 struct altq_pktattr
*);
75 static struct mbuf
*fifoq_dequeue(struct ifaltq
*, int);
76 static int fifoq_detach(fifoq_state_t
*);
77 static int fifoq_request(struct ifaltq
*, int, void *);
78 static void fifoq_purge(fifoq_state_t
*);
81 * fifoq device interface
86 fifoqopen(dev_t dev
, int flag
, int fmt
,
89 /* everything will be done when the queueing scheme is attached. */
94 * there are 2 ways to act on close.
95 * detach-all-on-close:
96 * use for the daemon style approach. if the daemon dies, all the
97 * resource will be released.
99 * use for the command style approach. (e.g. fifoq on/off)
101 * note: close is called not on every close but when the last reference
102 * is removed (only once with multiple simultaneous references.)
105 fifoqclose(dev_t dev
, int flag
, int fmt
,
111 while ((q
= fifoq_list
) != NULL
) {
113 err
= fifoq_detach(q
);
114 if (err
!= 0 && error
== 0)
122 fifoqioctl(dev_t dev
, ioctlcmd_t cmd
, void *addr
, int flag
,
126 struct fifoq_interface
*ifacep
;
130 /* check super-user privilege */
135 #if (__FreeBSD_version > 400000)
136 if ((error
= suser(p
)) != 0)
139 if ((error
= kauth_authorize_network(l
->l_cred
,
140 KAUTH_NETWORK_ALTQ
, KAUTH_REQ_NETWORK_ALTQ_FIFOQ
, NULL
,
149 ifacep
= (struct fifoq_interface
*)addr
;
150 if ((q
= altq_lookup(ifacep
->fifoq_ifname
, ALTQT_FIFOQ
))
155 error
= altq_enable(q
->q_ifq
);
159 ifacep
= (struct fifoq_interface
*)addr
;
160 if ((q
= altq_lookup(ifacep
->fifoq_ifname
, ALTQT_FIFOQ
))
165 error
= altq_disable(q
->q_ifq
);
168 case FIFOQ_IF_ATTACH
:
169 ifp
= ifunit(((struct fifoq_interface
*)addr
)->fifoq_ifname
);
175 /* allocate and initialize fifoq_state_t */
176 q
= malloc(sizeof(fifoq_state_t
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
182 q
->q_ifq
= &ifp
->if_snd
;
183 q
->q_head
= q
->q_tail
= NULL
;
185 q
->q_limit
= FIFOQ_LIMIT
;
188 * set FIFOQ to this ifnet structure.
190 error
= altq_attach(q
->q_ifq
, ALTQT_FIFOQ
, q
,
191 fifoq_enqueue
, fifoq_dequeue
, fifoq_request
,
198 /* add this state to the fifoq list */
199 q
->q_next
= fifoq_list
;
203 case FIFOQ_IF_DETACH
:
204 ifacep
= (struct fifoq_interface
*)addr
;
205 if ((q
= altq_lookup(ifacep
->fifoq_ifname
, ALTQT_FIFOQ
))
210 error
= fifoq_detach(q
);
215 struct fifoq_getstats
*q_stats
;
217 q_stats
= (struct fifoq_getstats
*)addr
;
218 if ((q
= altq_lookup(q_stats
->iface
.fifoq_ifname
,
219 ALTQT_FIFOQ
)) == NULL
) {
224 q_stats
->q_len
= q
->q_len
;
225 q_stats
->q_limit
= q
->q_limit
;
226 q_stats
->xmit_cnt
= q
->q_stats
.xmit_cnt
;
227 q_stats
->drop_cnt
= q
->q_stats
.drop_cnt
;
228 q_stats
->period
= q
->q_stats
.period
;
229 } while (/*CONSTCOND*/ 0);
234 struct fifoq_conf
*fc
;
237 fc
= (struct fifoq_conf
*)addr
;
238 if ((q
= altq_lookup(fc
->iface
.fifoq_ifname
,
239 ALTQT_FIFOQ
)) == NULL
) {
243 limit
= fc
->fifoq_limit
;
247 fc
->fifoq_limit
= limit
;
248 } while (/*CONSTCOND*/ 0);
259 * fifoq support routines
265 * returns: 0 when successfully queued.
266 * ENOBUFS when drop occurs.
269 fifoq_enqueue(struct ifaltq
*ifq
, struct mbuf
*m
,
270 struct altq_pktattr
*pktattr
)
272 fifoq_state_t
*q
= (fifoq_state_t
*)ifq
->altq_disc
;
274 /* if the queue is full, drop the incoming packet(drop-tail) */
275 if (q
->q_len
>= q
->q_limit
) {
277 PKTCNTR_ADD(&q
->q_stats
.drop_cnt
, m_pktlen(m
));
283 /* enqueue the packet at the taile of the queue */
285 if (q
->q_tail
== NULL
)
288 q
->q_tail
->m_nextpkt
= m
;
297 * must be called in splnet.
299 * returns: mbuf dequeued.
300 * NULL when no packet is available in the queue.
303 * ALTDQ_PEEK is provided for drivers which need to know the next packet
304 * to send in advance.
305 * when ALTDQ_PEEK is specified, the next packet to be dequeued is
306 * returned without dequeueing the packet.
307 * when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
308 * operation, the same packet should be returned.
311 fifoq_dequeue(struct ifaltq
*ifq
, int op
)
313 fifoq_state_t
*q
= (fifoq_state_t
*)ifq
->altq_disc
;
314 struct mbuf
*m
= NULL
;
316 if (op
== ALTDQ_POLL
)
319 if ((m
= q
->q_head
) == NULL
)
322 if ((q
->q_head
= m
->m_nextpkt
) == NULL
)
328 PKTCNTR_ADD(&q
->q_stats
.xmit_cnt
, m_pktlen(m
));
336 fifoq_request(struct ifaltq
*ifq
, int req
, void *arg
)
338 fifoq_state_t
*q
= (fifoq_state_t
*)ifq
->altq_disc
;
350 fifoq_detach(fifoq_state_t
*q
)
355 if (ALTQ_IS_ENABLED(q
->q_ifq
))
356 altq_disable(q
->q_ifq
);
360 if ((error
= altq_detach(q
->q_ifq
)))
364 fifoq_list
= q
->q_next
;
366 for (tmp
= fifoq_list
; tmp
!= NULL
; tmp
= tmp
->q_next
)
367 if (tmp
->q_next
== q
) {
368 tmp
->q_next
= q
->q_next
;
372 printf("fifoq_detach: no state in fifoq_list!\n");
381 * should be called in splnet or after disabling the fifoq.
384 fifoq_purge(fifoq_state_t
*q
)
388 while ((m
= q
->q_head
) != NULL
) {
389 q
->q_head
= m
->m_nextpkt
;
394 if (ALTQ_IS_ENABLED(q
->q_ifq
))
395 q
->q_ifq
->ifq_len
= 0;
400 static struct altqsw fifoq_sw
=
401 {"fifoq", fifoqopen
, fifoqclose
, fifoqioctl
};
403 ALTQ_MODULE(altq_fifoq
, ALTQT_FIFOQ
, &fifoq_sw
);
405 #endif /* KLD_MODULE */
407 #endif /* ALTQ3_COMPAT */
408 #endif /* ALTQ_FIFOQ */