1 /* $NetBSD: qop_priq.c,v 1.4 2001/08/22 08:52:37 itojun Exp $ */
2 /* $KAME: qop_priq.c,v 1.4 2001/12/03 08:20:55 kjc Exp $ */
5 * Sony Computer Science Laboratories, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY SONY CSL 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 SONY CSL 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
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/sockio.h>
32 #include <sys/ioctl.h>
33 #include <sys/fcntl.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
48 #include <altq/altq.h>
49 #include <altq/altq_priq.h>
53 static int qop_priq_enable_hook(struct ifinfo
*);
55 static int priq_attach(struct ifinfo
*);
56 static int priq_detach(struct ifinfo
*);
57 static int priq_clear(struct ifinfo
*);
58 static int priq_enable(struct ifinfo
*);
59 static int priq_disable(struct ifinfo
*);
60 static int priq_add_class(struct classinfo
*);
61 static int priq_modify_class(struct classinfo
*, void *);
62 static int priq_delete_class(struct classinfo
*);
63 static int priq_add_filter(struct fltrinfo
*);
64 static int priq_delete_filter(struct fltrinfo
*);
66 #define PRIQ_DEVICE "/dev/altq/priq"
68 static int priq_fd
= -1;
69 static int priq_refcount
= 0;
71 static struct qdisc_ops priq_qdisc
= {
86 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
92 priq_interface_parser(const char *ifname
, int argc
, char **argv
)
94 u_int bandwidth
= 100000000; /* 100Mbps */
102 if (EQUAL(*argv
, "bandwidth")) {
105 bandwidth
= atobps(*argv
);
106 } else if (EQUAL(*argv
, "tbrsize")) {
109 tbrsize
= atobytes(*argv
);
110 } else if (EQUAL(*argv
, "priq")) {
113 LOG(LOG_ERR
, 0, "Unknown keyword '%s'", *argv
);
119 if (qcmd_tbr_register(ifname
, bandwidth
, tbrsize
) != 0)
122 if (qcmd_priq_add_if(ifname
, bandwidth
, flags
) != 0)
128 priq_class_parser(const char *ifname
, const char *class_name
,
129 const char *parent_name
, int argc
, char **argv
)
131 int pri
= 0, qlimit
= 50;
132 int flags
= 0, error
;
135 if (EQUAL(*argv
, "priority")) {
138 pri
= strtoul(*argv
, NULL
, 0);
139 } else if (EQUAL(*argv
, "qlimit")) {
142 qlimit
= strtoul(*argv
, NULL
, 0);
143 } else if (EQUAL(*argv
, "default")) {
144 flags
|= PRCF_DEFAULTCLASS
;
145 } else if (EQUAL(*argv
, "red")) {
147 } else if (EQUAL(*argv
, "ecn")) {
149 } else if (EQUAL(*argv
, "rio")) {
151 } else if (EQUAL(*argv
, "cleardscp")) {
152 flags
|= PRCF_CLEARDSCP
;
155 "Unknown keyword '%s' in %s, line %d",
156 *argv
, altqconfigfile
, line_no
);
163 if ((flags
& PRCF_ECN
) && (flags
& (PRCF_RED
|PRCF_RIO
)) == 0)
166 error
= qcmd_priq_add_class(ifname
, class_name
, pri
, qlimit
, flags
);
169 LOG(LOG_ERR
, errno
, "priq_class_parser: %s",
180 qcmd_priq_add_if(const char *ifname
, u_int bandwidth
, int flags
)
184 error
= qop_priq_add_if(NULL
, ifname
, bandwidth
, flags
);
186 LOG(LOG_ERR
, errno
, "%s: can't add priq on interface '%s'",
187 qoperror(error
), ifname
);
192 qcmd_priq_add_class(const char *ifname
, const char *class_name
,
193 int pri
, int qlimit
, int flags
)
195 struct ifinfo
*ifinfo
;
198 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
199 error
= QOPERR_BADIF
;
202 error
= qop_priq_add_class(NULL
, class_name
, ifinfo
,
206 "priq: %s: can't add class '%s' on interface '%s'",
207 qoperror(error
), class_name
, ifname
);
212 qcmd_priq_modify_class(const char *ifname
, const char *class_name
,
213 int pri
, int qlimit
, int flags
)
215 struct ifinfo
*ifinfo
;
216 struct classinfo
*clinfo
;
218 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
219 return (QOPERR_BADIF
);
221 if ((clinfo
= clname2clinfo(ifinfo
, class_name
)) == NULL
)
222 return (QOPERR_BADCLASS
);
224 return qop_priq_modify_class(clinfo
, pri
, qlimit
, flags
);
231 qop_priq_add_if(struct ifinfo
**rp
, const char *ifname
,
232 u_int bandwidth
, int flags
)
234 struct ifinfo
*ifinfo
= NULL
;
235 struct priq_ifinfo
*priq_ifinfo
= NULL
;
238 if ((priq_ifinfo
= calloc(1, sizeof(*priq_ifinfo
))) == NULL
)
239 return (QOPERR_NOMEM
);
241 error
= qop_add_if(&ifinfo
, ifname
, bandwidth
,
242 &priq_qdisc
, priq_ifinfo
);
246 /* set enable hook */
247 ifinfo
->enable_hook
= qop_priq_enable_hook
;
254 if (priq_ifinfo
!= NULL
) {
257 ifinfo
->private = NULL
;
263 qop_priq_add_class(struct classinfo
**rp
, const char *class_name
,
264 struct ifinfo
*ifinfo
, int pri
, int qlimit
, int flags
)
266 struct classinfo
*clinfo
;
267 struct priq_ifinfo
*priq_ifinfo
;
268 struct priq_classinfo
*priq_clinfo
= NULL
;
271 priq_ifinfo
= ifinfo
->private;
272 if ((flags
& PRCF_DEFAULTCLASS
) && priq_ifinfo
->default_class
!= NULL
)
273 return (QOPERR_CLASS_INVAL
);
275 if ((priq_clinfo
= calloc(1, sizeof(*priq_clinfo
))) == NULL
) {
276 error
= QOPERR_NOMEM
;
280 priq_clinfo
->pri
= pri
;
281 priq_clinfo
->qlimit
= qlimit
;
282 priq_clinfo
->flags
= flags
;
284 if ((error
= qop_add_class(&clinfo
, class_name
, ifinfo
, NULL
,
288 if (flags
& PRCF_DEFAULTCLASS
)
289 priq_ifinfo
->default_class
= clinfo
;
296 if (priq_clinfo
!= NULL
) {
298 clinfo
->private = NULL
;
305 qop_priq_modify_class(struct classinfo
*clinfo
,
306 int pri
, int qlimit
, int flags
)
308 struct priq_classinfo
*priq_clinfo
, *parent_clinfo
;
311 priq_clinfo
= clinfo
->private;
312 if (clinfo
->parent
== NULL
)
313 return (QOPERR_CLASS_INVAL
);
314 parent_clinfo
= clinfo
->parent
->private;
316 priq_clinfo
->pri
= pri
;
317 priq_clinfo
->qlimit
= qlimit
;
318 priq_clinfo
->flags
= flags
;
320 error
= qop_modify_class(clinfo
, NULL
);
327 * sanity check at enabling priq:
328 * 1. there must one default class for an interface
331 qop_priq_enable_hook(struct ifinfo
*ifinfo
)
333 struct priq_ifinfo
*priq_ifinfo
;
335 priq_ifinfo
= ifinfo
->private;
336 if (priq_ifinfo
->default_class
== NULL
) {
337 LOG(LOG_ERR
, 0, "priq: no default class on interface %s!",
339 return (QOPERR_CLASS
);
345 * system call interfaces for qdisc_ops
348 priq_attach(struct ifinfo
*ifinfo
)
350 struct priq_interface iface
;
352 memset(&iface
, 0, sizeof(iface
));
353 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
356 (priq_fd
= open(PRIQ_DEVICE
, O_RDWR
)) < 0 &&
357 (priq_fd
= open_module(PRIQ_DEVICE
, O_RDWR
)) < 0) {
358 LOG(LOG_ERR
, errno
, "PRIQ open");
359 return (QOPERR_SYSCALL
);
363 memset(&iface
, 0, sizeof(iface
));
364 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
365 iface
.arg
= ifinfo
->bandwidth
;
367 if (ioctl(priq_fd
, PRIQ_IF_ATTACH
, &iface
) < 0)
368 return (QOPERR_SYSCALL
);
373 priq_detach(struct ifinfo
*ifinfo
)
375 struct priq_interface iface
;
377 memset(&iface
, 0, sizeof(iface
));
378 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
380 if (ioctl(priq_fd
, PRIQ_IF_DETACH
, &iface
) < 0)
381 return (QOPERR_SYSCALL
);
383 if (--priq_refcount
== 0) {
391 priq_clear(struct ifinfo
*ifinfo
)
393 struct priq_interface iface
;
395 memset(&iface
, 0, sizeof(iface
));
396 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
398 if (ioctl(priq_fd
, PRIQ_CLEAR
, &iface
) < 0)
399 return (QOPERR_SYSCALL
);
404 priq_enable(struct ifinfo
*ifinfo
)
406 struct priq_interface iface
;
408 memset(&iface
, 0, sizeof(iface
));
409 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
411 if (ioctl(priq_fd
, PRIQ_ENABLE
, &iface
) < 0)
412 return (QOPERR_SYSCALL
);
417 priq_disable(struct ifinfo
*ifinfo
)
419 struct priq_interface iface
;
421 memset(&iface
, 0, sizeof(iface
));
422 strncpy(iface
.ifname
, ifinfo
->ifname
, IFNAMSIZ
);
424 if (ioctl(priq_fd
, PRIQ_DISABLE
, &iface
) < 0)
425 return (QOPERR_SYSCALL
);
430 priq_add_class(struct classinfo
*clinfo
)
432 struct priq_add_class class_add
;
433 struct priq_classinfo
*priq_clinfo
;
434 struct priq_ifinfo
*priq_ifinfo
;
436 priq_ifinfo
= clinfo
->ifinfo
->private;
437 priq_clinfo
= clinfo
->private;
439 memset(&class_add
, 0, sizeof(class_add
));
440 strncpy(class_add
.iface
.ifname
, clinfo
->ifinfo
->ifname
, IFNAMSIZ
);
442 class_add
.pri
= priq_clinfo
->pri
;
443 class_add
.qlimit
= priq_clinfo
->qlimit
;
444 class_add
.flags
= priq_clinfo
->flags
;
445 if (ioctl(priq_fd
, PRIQ_ADD_CLASS
, &class_add
) < 0) {
446 clinfo
->handle
= PRIQ_NULLCLASS_HANDLE
;
447 return (QOPERR_SYSCALL
);
449 clinfo
->handle
= class_add
.class_handle
;
454 priq_modify_class(struct classinfo
*clinfo
, void *arg
)
456 struct priq_modify_class class_mod
;
457 struct priq_classinfo
*priq_clinfo
;
459 priq_clinfo
= clinfo
->private;
461 memset(&class_mod
, 0, sizeof(class_mod
));
462 strncpy(class_mod
.iface
.ifname
, clinfo
->ifinfo
->ifname
, IFNAMSIZ
);
463 class_mod
.class_handle
= clinfo
->handle
;
465 class_mod
.pri
= priq_clinfo
->pri
;
466 class_mod
.qlimit
= priq_clinfo
->qlimit
;
467 class_mod
.flags
= priq_clinfo
->flags
;
469 if (ioctl(priq_fd
, PRIQ_MOD_CLASS
, &class_mod
) < 0)
470 return (QOPERR_SYSCALL
);
475 priq_delete_class(struct classinfo
*clinfo
)
477 struct priq_delete_class class_delete
;
479 if (clinfo
->handle
== PRIQ_NULLCLASS_HANDLE
)
482 memset(&class_delete
, 0, sizeof(class_delete
));
483 strncpy(class_delete
.iface
.ifname
, clinfo
->ifinfo
->ifname
,
485 class_delete
.class_handle
= clinfo
->handle
;
487 if (ioctl(priq_fd
, PRIQ_DEL_CLASS
, &class_delete
) < 0)
488 return (QOPERR_SYSCALL
);
493 priq_add_filter(struct fltrinfo
*fltrinfo
)
495 struct priq_add_filter fltr_add
;
497 memset(&fltr_add
, 0, sizeof(fltr_add
));
498 strncpy(fltr_add
.iface
.ifname
, fltrinfo
->clinfo
->ifinfo
->ifname
,
500 fltr_add
.class_handle
= fltrinfo
->clinfo
->handle
;
501 fltr_add
.filter
= fltrinfo
->fltr
;
503 if (ioctl(priq_fd
, PRIQ_ADD_FILTER
, &fltr_add
) < 0)
504 return (QOPERR_SYSCALL
);
505 fltrinfo
->handle
= fltr_add
.filter_handle
;
510 priq_delete_filter(struct fltrinfo
*fltrinfo
)
512 struct priq_delete_filter fltr_del
;
514 memset(&fltr_del
, 0, sizeof(fltr_del
));
515 strncpy(fltr_del
.iface
.ifname
, fltrinfo
->clinfo
->ifinfo
->ifname
,
517 fltr_del
.filter_handle
= fltrinfo
->handle
;
519 if (ioctl(priq_fd
, PRIQ_DEL_FILTER
, &fltr_del
) < 0)
520 return (QOPERR_SYSCALL
);