1 /* $NetBSD: qop.c,v 1.8 2006/11/26 11:38:07 peter Exp $ */
2 /* $KAME: qop.c,v 1.11 2001/10/26 04:57:59 kjc Exp $ */
4 * Copyright (C) 1999-2000
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 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
36 #include <sys/linker.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
52 #include <altq/altq.h>
53 #include <altq/altq_red.h>
54 #include <altq/altq_rio.h>
55 #include <altq/altq_cdnr.h>
59 #define ALTQ_DEVICE "/dev/altq/altq"
60 #define RED_DEVICE "/dev/altq/red"
61 #define RIO_DEVICE "/dev/altq/rio"
62 #define CDNR_DEVICE "/dev/altq/cdnr"
64 #ifndef LIST_HEAD_INITIALIZER
65 #define LIST_HEAD_INITIALIZER(head) { NULL }
69 * token bucket regulator information
72 LIST_ENTRY(tbrinfo
) link
;
73 char ifname
[IFNAMSIZ
]; /* if name, e.g. "en0" */
74 struct tb_profile tb_prof
, otb_prof
;
81 /* a list of configured interfaces */
82 LIST_HEAD(qop_iflist
, ifinfo
) qop_iflist
= LIST_HEAD_INITIALIZER(&iflist
);
83 /* a list of configured token bucket regulators */
84 LIST_HEAD(tbr_list
, tbrinfo
) tbr_list
= LIST_HEAD_INITIALIZER(&tbr_list
);
89 static int get_ifmtu(const char *);
90 static void tbr_install(const char *);
91 static void tbr_deinstall(const char *);
92 static int add_filter_rule(struct ifinfo
*, struct fltrinfo
*,
94 static int remove_filter_rule(struct ifinfo
*,
96 static int filt_check_relation(struct flow_filter
*, struct flow_filter
*);
97 static int filt_disjoint(struct flow_filter
*, struct flow_filter
*);
98 static int filt_subset(struct flow_filter
*, struct flow_filter
*);
101 * QCMD (Queue Command) API
108 /* read config file and execute commands */
109 error
= qcmd_config();
113 error
= qcmd_enableall();
115 LOG(LOG_ERR
, errno
, "%s: qcmd_init failed", qoperror(error
));
120 qcmd_enable(const char *ifname
)
122 struct ifinfo
*ifinfo
;
125 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
126 error
= QOPERR_BADIF
;
129 error
= qop_enable(ifinfo
);
132 LOG(LOG_INFO
, 0, "%s enabled on interface %s (mtu:%d)",
133 ifinfo
->qdisc
->qname
, ifname
, ifinfo
->ifmtu
);
135 LOG(LOG_ERR
, errno
, "%s: enable failed!", qoperror(error
));
140 qcmd_disable(const char *ifname
)
142 struct ifinfo
*ifinfo
;
145 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
146 error
= QOPERR_BADIF
;
149 error
= qop_disable(ifinfo
);
152 LOG(LOG_ERR
, errno
, "%s: disable failed!", qoperror(error
));
159 struct ifinfo
*ifinfo
;
162 LIST_FOREACH(ifinfo
, &qop_iflist
, next
) {
163 if ((error
= qop_enable(ifinfo
)) != 0)
165 LOG(LOG_INFO
, 0, "%s enabled on interface %s (mtu:%d)",
166 ifinfo
->qdisc
->qname
, ifinfo
->ifname
, ifinfo
->ifmtu
);
174 struct ifinfo
*ifinfo
;
177 LIST_FOREACH(ifinfo
, &qop_iflist
, next
)
178 if ((lerr
= qop_disable(ifinfo
)) != 0)
185 qcmd_clear(const char *ifname
)
187 struct ifinfo
*ifinfo
;
190 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
191 error
= QOPERR_BADIF
;
194 error
= qop_clear(ifinfo
);
196 LOG(LOG_ERR
, errno
, "%s: clear failed!", qoperror(error
));
201 qcmd_destroyall(void)
203 while (!LIST_EMPTY(&qop_iflist
))
204 (void)qop_delete_if(LIST_FIRST(&qop_iflist
));
216 qcmd_delete_class(const char *ifname
, const char *clname
)
218 struct ifinfo
*ifinfo
;
219 struct classinfo
*clinfo
= NULL
;
222 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
223 error
= QOPERR_BADIF
;
226 (clinfo
= clname2clinfo(ifinfo
, clname
)) == NULL
)
227 error
= QOPERR_BADCLASS
;
230 error
= qop_delete_class(clinfo
);
232 LOG(LOG_ERR
, errno
, "%s: delete_class failed",
238 qcmd_add_filter(const char *ifname
, const char *clname
, const char *flname
,
239 const struct flow_filter
*fltr
)
241 struct ifinfo
*ifinfo
;
242 struct classinfo
*clinfo
= NULL
;
245 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
246 error
= QOPERR_BADIF
;
249 (clinfo
= clname2clinfo(ifinfo
, clname
)) == NULL
) {
251 * there is no matching class.
252 * check if it is for a traffic conditioner
254 if ((ifinfo
= input_ifname2ifinfo(ifname
)) == NULL
||
255 (clinfo
= clname2clinfo(ifinfo
, clname
)) == NULL
)
256 error
= QOPERR_BADCLASS
;
260 error
= qop_add_filter(NULL
, clinfo
, flname
, fltr
, NULL
);
263 LOG(LOG_ERR
, errno
, "%s: add filter failed!",
265 else if (IsDebug(DEBUG_ALTQ
)) {
266 LOG(LOG_DEBUG
, 0, "%s: add a filter %s to class %s",
267 ifname
, flname
? flname
: "(null)",
268 clname
? clname
: "(null)");
275 qcmd_delete_filter(const char *ifname
, const char *clname
, const char *flname
)
277 struct ifinfo
*ifinfo
;
278 struct classinfo
*clinfo
= NULL
;
279 struct fltrinfo
*fltrinfo
= NULL
;
282 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
283 error
= QOPERR_BADIF
;
286 (clinfo
= clname2clinfo(ifinfo
, clname
)) == NULL
) {
288 * there is no matching class.
289 * check if it is for a traffic conditioner
291 if ((ifinfo
= input_ifname2ifinfo(ifname
)) == NULL
||
292 (clinfo
= clname2clinfo(ifinfo
, clname
)) == NULL
)
293 error
= QOPERR_BADCLASS
;
297 (fltrinfo
= flname2flinfo(clinfo
, flname
)) == NULL
)
298 error
= QOPERR_BADFILTER
;
301 error
= qop_delete_filter(fltrinfo
);
303 LOG(LOG_ERR
, errno
, "%s: delete filter failed!",
309 qcmd_tbr_register(const char *ifname
, u_int rate
, u_int size
)
311 struct tbrinfo
*info
;
313 if ((info
= calloc(1, sizeof(struct tbrinfo
))) == NULL
)
314 return (QOPERR_NOMEM
);
316 strlcpy(info
->ifname
, ifname
, sizeof(info
->ifname
));
317 info
->tb_prof
.rate
= rate
;
318 info
->tb_prof
.depth
= size
;
320 LIST_INSERT_HEAD(&tbr_list
, info
, link
);
325 * QOP (Queue Operation) API
329 qop_add_if(struct ifinfo
**rp
, const char *ifname
, u_int bandwidth
,
330 struct qdisc_ops
*qdisc_ops
, void *if_private
)
332 struct ifinfo
*ifinfo
;
335 if (ifname2ifinfo(ifname
) != NULL
) {
336 LOG(LOG_ERR
, 0, "qop_add_if: %s already exists!", ifname
);
337 return (QOPERR_BADIF
);
340 if ((ifinfo
= calloc(1, sizeof(struct ifinfo
))) == NULL
)
341 return (QOPERR_NOMEM
);
342 ifinfo
->ifname
= strdup(ifname
);
343 ifinfo
->bandwidth
= bandwidth
;
345 if (ifname
[0] == '_')
346 /* input interface */
348 ifinfo
->ifindex
= get_ifindex(ifname
);
349 ifinfo
->ifmtu
= get_ifmtu(ifname
);
350 if (qdisc_ops
== NULL
)
351 ifinfo
->qdisc
= &nop_qdisc
; /* replace syscalls by nops */
353 ifinfo
->qdisc
= qdisc_ops
;
354 ifinfo
->private = if_private
;
355 LIST_INIT(&ifinfo
->cllist
);
356 LIST_INIT(&ifinfo
->fltr_rules
);
358 /* Link the interface info structure */
359 LIST_INSERT_HEAD(&qop_iflist
, ifinfo
, next
);
361 /* install token bucket regulator, if necessary */
364 /* attach the discipline to the interface */
365 if ((error
= (*ifinfo
->qdisc
->attach
)(ifinfo
)) != 0)
368 /* disable and clear the interface */
369 if (ifinfo
->qdisc
->disable
!= NULL
)
370 if ((error
= (*ifinfo
->qdisc
->disable
)(ifinfo
)) != 0)
372 if (ifinfo
->qdisc
->clear
!= NULL
)
373 if ((error
= (*ifinfo
->qdisc
->clear
)(ifinfo
)) != 0)
381 if (ifinfo
!= NULL
) {
382 LIST_REMOVE(ifinfo
, next
);
383 if (ifinfo
->ifname
!= NULL
)
384 free(ifinfo
->ifname
);
391 qop_delete_if(struct ifinfo
*ifinfo
)
393 (void)qop_disable(ifinfo
);
394 (void)qop_clear(ifinfo
);
396 if (ifinfo
->delete_hook
!= NULL
)
397 (*ifinfo
->delete_hook
)(ifinfo
);
399 /* remove this entry from qop_iflist */
400 LIST_REMOVE(ifinfo
, next
);
402 (void)(*ifinfo
->qdisc
->detach
)(ifinfo
);
404 /* deinstall token bucket regulator, if necessary */
405 tbr_deinstall(ifinfo
->ifname
);
407 if (ifinfo
->private != NULL
)
408 free(ifinfo
->private);
409 if (ifinfo
->ifname
!= NULL
)
410 free(ifinfo
->ifname
);
416 qop_enable(struct ifinfo
*ifinfo
)
420 if (ifinfo
->enable_hook
!= NULL
)
421 if ((error
= (*ifinfo
->enable_hook
)(ifinfo
)) != 0)
424 if (ifinfo
->qdisc
->enable
!= NULL
)
425 if ((error
= (*ifinfo
->qdisc
->enable
)(ifinfo
)) != 0)
432 qop_disable(struct ifinfo
*ifinfo
)
436 if (ifinfo
->qdisc
->disable
!= NULL
)
437 if ((error
= (*ifinfo
->qdisc
->disable
)(ifinfo
)) != 0)
444 qop_clear(struct ifinfo
*ifinfo
)
446 struct classinfo
*clinfo
;
448 /* free all classes and filters */
449 if (ifinfo
->ifname
[0] != '_') {
450 /* output interface. delete from leaf classes */
451 while (!LIST_EMPTY(&ifinfo
->cllist
)) {
452 LIST_FOREACH(clinfo
, &ifinfo
->cllist
, next
) {
453 if (clinfo
->child
!= NULL
)
455 qop_delete_class(clinfo
);
457 * the list has been changed,
458 * restart from the head
464 /* input interface. delete from parents */
465 struct classinfo
*root
= get_rootclass(ifinfo
);
467 while (!LIST_EMPTY(&ifinfo
->cllist
)) {
468 LIST_FOREACH(clinfo
, &ifinfo
->cllist
, next
)
469 if (clinfo
->parent
== root
) {
470 qop_delete_cdnr(clinfo
);
473 if (root
->child
!= NULL
)
474 qop_delete_class(root
);
478 /* clear the interface */
479 if (ifinfo
->qdisc
->clear
!= NULL
)
480 return (*ifinfo
->qdisc
->clear
)(ifinfo
);
485 qop_add_class(struct classinfo
**rp
, const char *clname
,
486 struct ifinfo
*ifinfo
, struct classinfo
*parent
,
489 struct classinfo
*clinfo
;
492 if ((clinfo
= calloc(1, sizeof(*clinfo
))) == NULL
)
493 return (QOPERR_NOMEM
);
496 clinfo
->clname
= strdup(clname
);
498 clinfo
->clname
= strdup("(null)"); /* dummy name */
499 clinfo
->ifinfo
= ifinfo
;
500 clinfo
->private = class_private
;
501 clinfo
->parent
= parent
;
502 clinfo
->child
= NULL
;
503 LIST_INIT(&clinfo
->fltrlist
);
505 if ((error
= (*ifinfo
->qdisc
->add_class
)(clinfo
)) != 0)
508 /* link classinfo in lists */
509 LIST_INSERT_HEAD(&ifinfo
->cllist
, clinfo
, next
);
511 if (parent
!= NULL
) {
512 clinfo
->sibling
= parent
->child
;
513 clinfo
->parent
->child
= clinfo
;
521 if (clinfo
!= NULL
) {
522 if (clinfo
->clname
!= NULL
)
523 free(clinfo
->clname
);
530 qop_modify_class(struct classinfo
*clinfo
, void *arg
)
532 return (*clinfo
->ifinfo
->qdisc
->modify_class
)(clinfo
, arg
);
536 qop_delete_class(struct classinfo
*clinfo
)
538 struct ifinfo
*ifinfo
= clinfo
->ifinfo
;
539 struct classinfo
*prev
;
542 /* a class to be removed should not have a child */
543 if (clinfo
->child
!= NULL
)
544 return (QOPERR_CLASS_PERM
);
546 /* remove filters associated to this class */
547 while (!LIST_EMPTY(&clinfo
->fltrlist
))
548 (void)qop_delete_filter(LIST_FIRST(&clinfo
->fltrlist
));
550 if (clinfo
->delete_hook
!= NULL
)
551 (*clinfo
->delete_hook
)(clinfo
);
553 /* remove class info from the interface */
554 LIST_REMOVE(clinfo
, next
);
556 /* remove this class from the child list */
557 if (clinfo
->parent
!= NULL
) {
558 if (clinfo
->parent
->child
== clinfo
)
559 clinfo
->parent
->child
= clinfo
->sibling
;
560 else for (prev
= clinfo
->parent
->child
; prev
->sibling
!= NULL
;
561 prev
= prev
->sibling
)
562 if (prev
->sibling
== clinfo
) {
563 prev
->sibling
= clinfo
->sibling
;
568 /* delete class from kernel */
569 if ((error
= (*ifinfo
->qdisc
->delete_class
)(clinfo
)) != 0)
572 if (clinfo
->private != NULL
)
573 free(clinfo
->private);
574 if (clinfo
->clname
!= NULL
)
575 free(clinfo
->clname
);
581 qop_add_filter(struct fltrinfo
**rp
, struct classinfo
*clinfo
,
582 const char *flname
, const struct flow_filter
*fltr
,
583 struct fltrinfo
**conflict
)
585 struct ifinfo
*ifinfo
;
586 struct fltrinfo
*fltrinfo
;
589 if ((fltrinfo
= calloc(1, sizeof(*fltrinfo
))) == NULL
)
590 return (QOPERR_NOMEM
);
592 fltrinfo
->clinfo
= clinfo
;
593 fltrinfo
->fltr
= *fltr
;
596 fltrinfo
->line_no
= line_no
; /* XXX */
597 fltrinfo
->dontwarn
= filter_dontwarn
; /* XXX */
600 fltrinfo
->flname
= strdup(flname
);
602 fltrinfo
->flname
= strdup("(null)"); /* dummy name */
604 /* check and save the filter */
605 ifinfo
= clinfo
->ifinfo
;
606 if ((error
= add_filter_rule(ifinfo
, fltrinfo
, conflict
)) != 0)
609 /* install the filter to the kernel */
610 if ((error
= (*ifinfo
->qdisc
->add_filter
)(fltrinfo
)) != 0) {
611 remove_filter_rule(ifinfo
, fltrinfo
);
615 /* link fltrinfo onto fltrlist of the class */
616 LIST_INSERT_HEAD(&clinfo
->fltrlist
, fltrinfo
, next
);
623 if (fltrinfo
!= NULL
) {
624 if (fltrinfo
->flname
!= NULL
)
625 free(fltrinfo
->flname
);
632 qop_delete_filter(struct fltrinfo
*fltrinfo
)
634 struct ifinfo
*ifinfo
;
635 struct classinfo
*clinfo
;
638 /* remove filter info from the class */
639 clinfo
= fltrinfo
->clinfo
;
640 ifinfo
= clinfo
->ifinfo
;
643 /* remove the entry from fltrlist of the class */
644 LIST_REMOVE(fltrinfo
, next
);
646 remove_filter_rule(ifinfo
, fltrinfo
);
648 /* delete filter from kernel */
649 if ((error
= (*ifinfo
->qdisc
->delete_filter
)(fltrinfo
)) != 0)
652 if (fltrinfo
->flname
)
653 free(fltrinfo
->flname
);
659 qoperror(int qoperrno
)
663 if (qoperrno
<= QOPERR_MAX
)
664 return (qop_errlist
[qoperrno
]);
665 snprintf(buf
, sizeof(buf
), "unknown error %d", qoperrno
);
673 ifname2ifinfo(const char *ifname
)
675 struct ifinfo
*ifinfo
;
677 LIST_FOREACH(ifinfo
, &qop_iflist
, next
)
678 if (ifinfo
->ifname
!= NULL
&&
679 strcmp(ifinfo
->ifname
, ifname
) == 0)
685 input_ifname2ifinfo(const char *ifname
)
687 struct ifinfo
*ifinfo
;
689 LIST_FOREACH(ifinfo
, &qop_iflist
, next
)
690 if (ifinfo
->ifname
[0] == '_' &&
691 strcmp(ifinfo
->ifname
+1, ifname
) == 0)
697 clname2clinfo(const struct ifinfo
*ifinfo
, const char *clname
)
699 struct classinfo
*clinfo
;
701 LIST_FOREACH(clinfo
, &ifinfo
->cllist
, next
)
702 if (clinfo
->clname
!= NULL
&&
703 strcmp(clinfo
->clname
, clname
) == 0)
709 clhandle2clinfo(struct ifinfo
*ifinfo
, u_long handle
)
711 struct classinfo
*clinfo
;
713 LIST_FOREACH(clinfo
, &ifinfo
->cllist
, next
)
714 if (clinfo
->handle
== handle
)
720 flname2flinfo(const struct classinfo
*clinfo
, const char *flname
)
722 struct fltrinfo
*fltrinfo
;
724 LIST_FOREACH(fltrinfo
, &clinfo
->fltrlist
, next
)
725 if (fltrinfo
->flname
!= NULL
&&
726 strcmp(fltrinfo
->flname
, flname
) == 0)
732 flhandle2fltrinfo(struct ifinfo
*ifinfo
, u_long handle
)
734 struct fltrinfo
*fltrinfo
;
736 LIST_FOREACH(fltrinfo
, &ifinfo
->fltr_rules
, nextrule
)
737 if (fltrinfo
->handle
== handle
)
743 is_q_enabled(const char *ifname
)
745 struct ifinfo
*ifinfo
;
747 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
)
749 return (ifinfo
->enabled
);
753 * functions to walk through a class tree:
755 * for (clinfo = get_rootclass(ifinfo);
756 * clinfo != NULL; clinfo = get_nextclass(clinfo)) {
760 struct classinfo
*get_rootclass(struct ifinfo
*ifinfo
)
762 struct classinfo
*clinfo
;
764 /* find a class without parent */
765 LIST_FOREACH(clinfo
, &ifinfo
->cllist
, next
)
766 if (clinfo
->parent
== NULL
)
771 /* return next class in the tree */
772 struct classinfo
*get_nextclass(struct classinfo
*clinfo
)
774 struct classinfo
*next
;
776 if (clinfo
->child
!= NULL
)
777 next
= clinfo
->child
;
778 else if (clinfo
->sibling
!= NULL
)
779 next
= clinfo
->sibling
;
782 while ((next
= next
->parent
) != NULL
)
784 next
= next
->sibling
;
792 atobps(const char *s
)
797 bandwidth
= strtod(s
, &cp
);
799 if (*cp
== 'K' || *cp
== 'k')
801 else if (*cp
== 'M' || *cp
== 'm')
802 bandwidth
*= 1000000;
803 else if (*cp
== 'G' || *cp
== 'g')
804 bandwidth
*= 1000000000;
808 return ((u_long
)bandwidth
);
812 atobytes(const char *s
)
817 bytes
= strtod(s
, &cp
);
819 if (*cp
== 'K' || *cp
== 'k')
821 else if (*cp
== 'M' || *cp
== 'm')
822 bytes
*= 1024 * 1024;
823 else if (*cp
== 'G' || *cp
== 'g')
824 bytes
*= 1024 * 1024 * 1024;
828 return ((u_long
)bytes
);
832 get_ifmtu(const char *ifname
)
837 struct if_data ifdata
;
840 mtu
= 512; /* default MTU */
842 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
844 strncpy(ifr
.ifr_name
, ifname
, sizeof ifr
.ifr_name
);
846 ifr
.ifr_data
= (caddr_t
)&ifdata
;
847 if (ioctl(s
, SIOCGIFDATA
, (caddr_t
)&ifr
) == 0)
848 mtu
= ifdata
.ifi_mtu
;
850 if (ioctl(s
, SIOCGIFMTU
, (caddr_t
)&ifr
) == 0)
858 tbr_install(const char *ifname
)
860 struct tbrinfo
*info
;
864 LIST_FOREACH(info
, &tbr_list
, link
)
865 if (strcmp(info
->ifname
, ifname
) == 0)
869 if (info
->tb_prof
.rate
== 0 || info
->installed
)
872 /* get the current token bucket regulator */
873 if ((fd
= open(ALTQ_DEVICE
, O_RDWR
)) < 0)
874 err(1, "can't open altq device");
875 strncpy(req
.ifname
, ifname
, IFNAMSIZ
-1);
876 if (ioctl(fd
, ALTQTBRGET
, &req
) < 0)
877 err(1, "ALTQTBRGET for interface %s", req
.ifname
);
879 /* save the current values */
880 info
->otb_prof
.rate
= req
.tb_prof
.rate
;
881 info
->otb_prof
.depth
= req
.tb_prof
.depth
;
884 * if tbr is not specified in the config file and tbr is already
885 * configured, do not change.
887 if (req
.tb_prof
.rate
!= 0) {
889 "tbr is already installed on %s,\n"
890 " using the current setting (rate:%.2fM size:%.2fK).",
892 (double)req
.tb_prof
.rate
/1000000.0,
893 (double)req
.tb_prof
.depth
/1024.0);
898 /* if the new size is not specified, use heuristics */
899 if (info
->tb_prof
.depth
== 0) {
902 rate
= info
->tb_prof
.rate
;
903 if (rate
<= 1*1000*1000)
905 else if (rate
<= 10*1000*1000)
907 else if (rate
<= 200*1000*1000)
911 size
= size
* 1500; /* assume the default mtu is 1500 */
912 info
->tb_prof
.depth
= size
;
915 /* install the new tbr */
916 strncpy(req
.ifname
, ifname
, IFNAMSIZ
-1);
917 req
.tb_prof
.rate
= info
->tb_prof
.rate
;
918 req
.tb_prof
.depth
= info
->tb_prof
.depth
;
919 if (ioctl(fd
, ALTQTBRSET
, &req
) < 0)
920 err(1, "ALTQTBRSET for interface %s", req
.ifname
);
922 "tbr installed on %s (rate:%.2fM size:%.2fK)",
924 (double)info
->tb_prof
.rate
/1000000.0,
925 (double)info
->tb_prof
.depth
/1024.0);
931 tbr_deinstall(const char *ifname
)
933 struct tbrinfo
*info
;
937 LIST_FOREACH(info
, &tbr_list
, link
)
938 if (strcmp(info
->ifname
, ifname
) == 0)
943 /* if we installed tbr, restore the old values */
944 if (info
->installed
!= 0) {
945 strncpy(req
.ifname
, ifname
, IFNAMSIZ
-1);
946 req
.tb_prof
.rate
= info
->otb_prof
.rate
;
947 req
.tb_prof
.depth
= info
->otb_prof
.depth
;
948 if ((fd
= open(ALTQ_DEVICE
, O_RDWR
)) < 0)
949 err(1, "can't open altq device");
950 if (ioctl(fd
, ALTQTBRSET
, &req
) < 0)
951 err(1, "ALTQTBRSET for interface %s", req
.ifname
);
954 LIST_REMOVE(info
, link
);
959 print_filter(const struct flow_filter
*filt
)
961 if (filt
->ff_flow
.fi_family
== AF_INET
) {
962 struct in_addr in_addr
;
964 in_addr
.s_addr
= filt
->ff_flow
.fi_dst
.s_addr
;
966 " Filter Dest Addr: %s (mask %#x) Port: %d",
967 inet_ntoa(in_addr
), ntoh32(filt
->ff_mask
.mask_dst
.s_addr
),
968 ntoh16(filt
->ff_flow
.fi_dport
));
969 in_addr
.s_addr
= filt
->ff_flow
.fi_src
.s_addr
;
971 " Src Addr: %s (mask %#x) Port: %d",
972 inet_ntoa(in_addr
), ntoh32(filt
->ff_mask
.mask_src
.s_addr
),
973 ntoh16(filt
->ff_flow
.fi_sport
));
974 LOG(LOG_DEBUG
, 0, " Protocol: %d TOS %#x (mask %#x)",
975 filt
->ff_flow
.fi_proto
, filt
->ff_flow
.fi_tos
,
976 filt
->ff_mask
.mask_tos
);
979 else if (filt
->ff_flow
.fi_family
== AF_INET6
) {
980 char str1
[INET6_ADDRSTRLEN
], str2
[INET6_ADDRSTRLEN
];
981 const struct flow_filter6
*sfilt6
;
983 sfilt6
= (const struct flow_filter6
*)filt
;
984 LOG(LOG_DEBUG
, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d",
985 inet_ntop(AF_INET6
, &sfilt6
->ff_flow6
.fi6_dst
,
987 inet_ntop(AF_INET6
, &sfilt6
->ff_mask6
.mask6_dst
,
989 ntoh16(sfilt6
->ff_flow6
.fi6_dport
));
990 LOG(LOG_DEBUG
, 0, " Src Addr: %s (mask %s) Port: %d",
991 inet_ntop(AF_INET6
, &sfilt6
->ff_flow6
.fi6_src
,
993 inet_ntop(AF_INET6
, &sfilt6
->ff_mask6
.mask6_src
,
995 ntoh16(sfilt6
->ff_flow6
.fi6_sport
));
996 LOG(LOG_DEBUG
, 0, " Protocol: %d TCLASS %#x (mask %#x)",
997 sfilt6
->ff_flow6
.fi6_proto
, sfilt6
->ff_flow6
.fi6_tclass
,
998 sfilt6
->ff_mask6
.mask6_tclass
);
1004 * functions to check the filter-rules.
1005 * when a new filter is added, we check the relation to the existing filters
1006 * and if some inconsistency is found, produce an error or a warning message.
1008 * filter matching is performed from the head of the list.
1010 * S: a set of packets that filter s matches
1011 * T: a set of packets that filter t matches
1012 * filter relations are:
1013 * disjoint: S ^ T = empty
1015 * intersect: S ^ T = not empty
1017 * a new filter is disjoint or subset of the existing filters --> ok
1018 * a new filter is superset of an existing filter --> order problem
1019 * a new filter intersect an existing filter --> warning
1021 * port-intersect: a special case we don't make warning
1022 * - intersection is only port numbers
1023 * - one specifies src port and the other specifies dst port
1024 * there must be no packet with well-known port numbers in
1025 * both src and dst ports. so this is ok.
1028 #define FILT_DISJOINT 1
1029 #define FILT_SUBSET 2
1030 #define FILT_SUPERSET 3
1031 #define FILT_INTERSECT 4
1032 #define FILT_PORTINTERSECT 5
1035 add_filter_rule(struct ifinfo
*ifinfo
, struct fltrinfo
*fltrinfo
,
1036 struct fltrinfo
**conflict
)
1038 struct fltrinfo
*fp
, *front
, *back
, *prev
= NULL
;
1041 LIST_FOREACH(fp
, &ifinfo
->fltr_rules
, nextrule
) {
1042 if (fp
->fltr
.ff_ruleno
> fltrinfo
->fltr
.ff_ruleno
) {
1051 relation
= filt_check_relation(&front
->fltr
, &back
->fltr
);
1059 if (front
->dontwarn
== 0 && back
->dontwarn
== 0)
1061 "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!",
1062 front
->clinfo
->clname
, front
->line_no
,
1063 back
->clinfo
->clname
, back
->line_no
);
1065 if (conflict
!= NULL
)
1067 return (QOPERR_FILTER_SHADOW
);
1068 case FILT_PORTINTERSECT
:
1070 case FILT_INTERSECT
:
1072 * if the intersecting two filters beloging to the
1073 * same class, it's ok.
1075 if (front
->clinfo
== back
->clinfo
)
1077 if (front
->dontwarn
== 0 && back
->dontwarn
== 0)
1079 "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d",
1080 front
->clinfo
->clname
, front
->line_no
,
1081 back
->clinfo
->clname
, back
->line_no
);
1087 LIST_INSERT_HEAD(&ifinfo
->fltr_rules
, fltrinfo
, nextrule
);
1089 LIST_INSERT_AFTER(prev
, fltrinfo
, nextrule
);
1094 remove_filter_rule(struct ifinfo
*ifinfo
, struct fltrinfo
*fltrinfo
)
1096 LIST_REMOVE(fltrinfo
, nextrule
);
1101 filt_check_relation(struct flow_filter
*front
, struct flow_filter
*back
)
1105 if (front
->ff_flow
.fi_family
!= back
->ff_flow
.fi_family
)
1106 return (FILT_DISJOINT
);
1108 if (filt_disjoint(front
, back
))
1109 return (FILT_DISJOINT
);
1111 if ((rval
= filt_subset(front
, back
)) == 1)
1112 return (FILT_SUBSET
);
1114 if (filt_subset(back
, front
) == 1)
1115 return (FILT_SUPERSET
);
1118 return (FILT_PORTINTERSECT
);
1120 return (FILT_INTERSECT
);
1124 filt_disjoint(struct flow_filter
*front
, struct flow_filter
*back
)
1129 if (front
->ff_flow
.fi_family
== AF_INET
) {
1130 if (front
->ff_flow
.fi_proto
!= 0 && back
->ff_flow
.fi_proto
!= 0
1131 && front
->ff_flow
.fi_proto
!= back
->ff_flow
.fi_proto
)
1133 if (front
->ff_flow
.fi_sport
!= 0 && back
->ff_flow
.fi_sport
!= 0
1134 && front
->ff_flow
.fi_sport
!= back
->ff_flow
.fi_sport
)
1136 if (front
->ff_flow
.fi_dport
!= 0 && back
->ff_flow
.fi_dport
!= 0
1137 && front
->ff_flow
.fi_dport
!= back
->ff_flow
.fi_dport
)
1139 if (front
->ff_flow
.fi_gpi
!= 0 && back
->ff_flow
.fi_gpi
!= 0
1140 && front
->ff_flow
.fi_gpi
!= back
->ff_flow
.fi_gpi
)
1142 if (front
->ff_flow
.fi_src
.s_addr
!= 0 &&
1143 back
->ff_flow
.fi_src
.s_addr
!= 0) {
1144 mask
= front
->ff_mask
.mask_src
.s_addr
&
1145 back
->ff_mask
.mask_src
.s_addr
;
1146 if ((front
->ff_flow
.fi_src
.s_addr
& mask
) !=
1147 (back
->ff_flow
.fi_src
.s_addr
& mask
))
1150 if (front
->ff_flow
.fi_dst
.s_addr
!= 0 &&
1151 back
->ff_flow
.fi_dst
.s_addr
!= 0) {
1152 mask
= front
->ff_mask
.mask_dst
.s_addr
&
1153 back
->ff_mask
.mask_dst
.s_addr
;
1154 if ((front
->ff_flow
.fi_dst
.s_addr
& mask
) !=
1155 (back
->ff_flow
.fi_dst
.s_addr
& mask
))
1158 if (front
->ff_flow
.fi_tos
!= 0 && back
->ff_flow
.fi_tos
!= 0) {
1159 tosmask
= front
->ff_mask
.mask_tos
&
1160 back
->ff_mask
.mask_tos
;
1161 if ((front
->ff_flow
.fi_tos
& tosmask
) !=
1162 (back
->ff_flow
.fi_tos
& tosmask
))
1168 else if (front
->ff_flow
.fi_family
== AF_INET6
) {
1169 struct flow_filter6
*front6
, *back6
;
1172 front6
= (struct flow_filter6
*)front
;
1173 back6
= (struct flow_filter6
*)back
;
1175 if (front6
->ff_flow6
.fi6_proto
!= 0 &&
1176 back6
->ff_flow6
.fi6_proto
!= 0 &&
1177 front6
->ff_flow6
.fi6_proto
!= back6
->ff_flow6
.fi6_proto
)
1179 if (front6
->ff_flow6
.fi6_flowlabel
!= 0 &&
1180 back6
->ff_flow6
.fi6_flowlabel
!= 0 &&
1181 front6
->ff_flow6
.fi6_flowlabel
!=
1182 back6
->ff_flow6
.fi6_flowlabel
)
1184 if (front6
->ff_flow6
.fi6_sport
!= 0 &&
1185 back6
->ff_flow6
.fi6_sport
!= 0 &&
1186 front6
->ff_flow6
.fi6_sport
!= back6
->ff_flow6
.fi6_sport
)
1188 if (front6
->ff_flow6
.fi6_dport
!= 0 &&
1189 back6
->ff_flow6
.fi6_dport
!= 0 &&
1190 front6
->ff_flow6
.fi6_dport
!= back6
->ff_flow6
.fi6_dport
)
1192 if (front6
->ff_flow6
.fi6_gpi
!= 0 &&
1193 back6
->ff_flow6
.fi6_gpi
!= 0 &&
1194 front6
->ff_flow6
.fi6_gpi
!= back6
->ff_flow6
.fi6_gpi
)
1196 if (!IN6_IS_ADDR_UNSPECIFIED(&front6
->ff_flow6
.fi6_src
) &&
1197 !IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_src
)) {
1198 for (i
=0; i
<4; i
++) {
1199 mask
= IN6ADDR32(&front6
->ff_mask6
.mask6_src
, i
)
1200 & IN6ADDR32(&back6
->ff_mask6
.mask6_src
, i
);
1201 if ((IN6ADDR32(&front6
->ff_flow6
.fi6_src
, i
) & mask
) !=
1202 (IN6ADDR32(&back6
->ff_flow6
.fi6_src
, i
) & mask
))
1206 if (!IN6_IS_ADDR_UNSPECIFIED(&front6
->ff_flow6
.fi6_dst
) &&
1207 !IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_dst
)) {
1208 for (i
=0; i
<4; i
++) {
1209 mask
= IN6ADDR32(&front6
->ff_mask6
.mask6_dst
, i
)
1210 & IN6ADDR32(&back6
->ff_mask6
.mask6_dst
, i
);
1211 if ((IN6ADDR32(&front6
->ff_flow6
.fi6_dst
, i
) & mask
) !=
1212 (IN6ADDR32(&back6
->ff_flow6
.fi6_dst
, i
) & mask
))
1216 if (front6
->ff_flow6
.fi6_tclass
!= 0 &&
1217 back6
->ff_flow6
.fi6_tclass
!= 0) {
1218 tosmask
= front6
->ff_mask6
.mask6_tclass
&
1219 back6
->ff_mask6
.mask6_tclass
;
1220 if ((front6
->ff_flow6
.fi6_tclass
& tosmask
) !=
1221 (back6
->ff_flow6
.fi6_tclass
& tosmask
))
1231 * check if "front" is a subset of "back". assumes they are not disjoint
1232 * return value 0: not a subset
1234 * 2: subset except src & dst ports
1235 * (possible port-intersect)
1238 filt_subset(struct flow_filter
*front
, struct flow_filter
*back
)
1240 u_int16_t srcport
, dstport
;
1242 if (front
->ff_flow
.fi_family
== AF_INET
) {
1243 if (front
->ff_flow
.fi_proto
== 0 &&
1244 back
->ff_flow
.fi_proto
!= 0)
1246 if (front
->ff_flow
.fi_gpi
== 0 && back
->ff_flow
.fi_gpi
!= 0)
1248 if (front
->ff_flow
.fi_src
.s_addr
== 0) {
1249 if (back
->ff_flow
.fi_src
.s_addr
!= 0)
1251 } else if (back
->ff_flow
.fi_src
.s_addr
!= 0 &&
1252 (~front
->ff_mask
.mask_src
.s_addr
&
1253 back
->ff_mask
.mask_src
.s_addr
))
1255 if (front
->ff_flow
.fi_dst
.s_addr
== 0) {
1256 if (back
->ff_flow
.fi_dst
.s_addr
!= 0)
1258 } else if (back
->ff_flow
.fi_dst
.s_addr
!= 0 &&
1259 (~front
->ff_mask
.mask_dst
.s_addr
&
1260 back
->ff_mask
.mask_dst
.s_addr
))
1262 if (~front
->ff_mask
.mask_tos
& back
->ff_mask
.mask_tos
)
1265 if (front
->ff_flow
.fi_sport
== 0 &&
1266 back
->ff_flow
.fi_sport
!= 0) {
1267 srcport
= ntohs(back
->ff_flow
.fi_sport
);
1268 dstport
= ntohs(front
->ff_flow
.fi_dport
);
1269 if (dstport
> 0 /* && dstport < 1024 */ &&
1270 srcport
> 0 /* && srcport < 1024 */)
1274 if (front
->ff_flow
.fi_dport
== 0 &&
1275 back
->ff_flow
.fi_dport
!= 0) {
1276 dstport
= ntohs(back
->ff_flow
.fi_dport
);
1277 srcport
= ntohs(front
->ff_flow
.fi_sport
);
1278 if (srcport
> 0 /* && srcport < 1024 */ &&
1279 dstport
> 0 /* && dstport < 1024 */)
1287 else if (front
->ff_flow
.fi_family
== AF_INET6
) {
1288 struct flow_filter6
*front6
, *back6
;
1291 front6
= (struct flow_filter6
*)front
;
1292 back6
= (struct flow_filter6
*)back
;
1294 if (front6
->ff_flow6
.fi6_proto
== 0 &&
1295 back6
->ff_flow6
.fi6_proto
!= 0)
1297 if (front6
->ff_flow6
.fi6_flowlabel
== 0 &&
1298 back6
->ff_flow6
.fi6_flowlabel
!= 0)
1300 if (front6
->ff_flow6
.fi6_gpi
== 0 &&
1301 back6
->ff_flow6
.fi6_gpi
!= 0)
1304 if (IN6_IS_ADDR_UNSPECIFIED(&front6
->ff_flow6
.fi6_src
)) {
1305 if (!IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_src
))
1307 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_src
))
1309 if (~IN6ADDR32(&front6
->ff_mask6
.mask6_src
, i
) &
1310 IN6ADDR32(&back6
->ff_mask6
.mask6_src
, i
))
1312 if (IN6_IS_ADDR_UNSPECIFIED(&front6
->ff_flow6
.fi6_dst
)) {
1313 if (!IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_dst
))
1315 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6
->ff_flow6
.fi6_dst
))
1317 if (~IN6ADDR32(&front6
->ff_mask6
.mask6_dst
, i
) &
1318 IN6ADDR32(&back6
->ff_mask6
.mask6_dst
, i
))
1321 if (~front6
->ff_mask6
.mask6_tclass
&
1322 back6
->ff_mask6
.mask6_tclass
)
1325 if (front6
->ff_flow6
.fi6_sport
== 0 &&
1326 back6
->ff_flow6
.fi6_sport
!= 0) {
1327 srcport
= ntohs(back6
->ff_flow6
.fi6_sport
);
1328 dstport
= ntohs(front6
->ff_flow6
.fi6_dport
);
1329 if (dstport
> 0 /* && dstport < 1024 */ &&
1330 srcport
> 0 /* && srcport < 1024 */)
1334 if (front6
->ff_flow6
.fi6_dport
== 0 &&
1335 back6
->ff_flow6
.fi6_dport
!= 0) {
1336 dstport
= ntohs(back6
->ff_flow6
.fi6_dport
);
1337 srcport
= ntohs(front6
->ff_flow6
.fi6_sport
);
1338 if (srcport
> 0 /* && srcport < 1024 */ &&
1339 dstport
> 0 /* && dstport < 1024 */)
1350 * setting RED or RIO default parameters
1353 qop_red_set_defaults(int th_min
, int th_max
, int inv_pmax
)
1355 struct redparams params
;
1358 if ((fd
= open(RED_DEVICE
, O_RDWR
)) < 0) {
1359 LOG(LOG_ERR
, errno
, "RED open");
1360 return (QOPERR_SYSCALL
);
1363 params
.th_min
= th_min
;
1364 params
.th_max
= th_max
;
1365 params
.inv_pmax
= inv_pmax
;
1367 if (ioctl(fd
, RED_SETDEFAULTS
, ¶ms
) < 0) {
1368 LOG(LOG_ERR
, errno
, "RED_SETDEFAULTS");
1369 return (QOPERR_SYSCALL
);
1377 qop_rio_set_defaults(struct redparams
*params
)
1382 for (i
= 1; i
< RIO_NDROPPREC
; i
++) {
1383 if (params
[i
].th_max
> params
[i
-1].th_min
)
1385 "warning: overlap found in RIO thresholds");
1388 if ((fd
= open(RIO_DEVICE
, O_RDWR
)) < 0) {
1389 LOG(LOG_ERR
, errno
, "RIO open");
1390 return (QOPERR_SYSCALL
);
1393 if (ioctl(fd
, RIO_SETDEFAULTS
, params
) < 0) {
1394 LOG(LOG_ERR
, errno
, "RIO_SETDEFAULTS");
1395 return (QOPERR_SYSCALL
);
1403 * try to load and open KLD module
1404 * (also check the altq device file)
1407 open_module(const char *dvname
, int flags
)
1409 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
1410 char modname
[64], filename
[MAXPATHLEN
], *cp
;
1415 /* check if the altq device exists */
1416 if (stat(dvname
, &sbuf
) < 0) {
1417 LOG(LOG_ERR
, errno
, "can't access %s!", dvname
);
1421 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000)
1422 /* turn discipline name into module name */
1423 strlcpy(modname
, "altq_", sizeof(modname
));
1424 if ((cp
= strrchr(devname
, '/')) == NULL
)
1426 strlcat(modname
, cp
+ 1, sizeof(modname
));
1428 /* check if the kld module exists */
1429 snprintf(filename
, sizeof(filename
), "/modules/%s.ko", modname
);
1430 if (stat(filename
, &sbuf
) < 0) {
1431 /* module file doesn't exist */
1435 if (kldload(modname
) < 0) {
1436 LOG(LOG_ERR
, errno
, "kldload %s failed!", modname
);
1440 /* successfully loaded, open the device */
1441 LOG(LOG_INFO
, 0, "kld module %s loaded", modname
);
1442 fd
= open(devname
, flags
);