1 /* $NetBSD: parser.c,v 1.9 2003/02/01 17:13:14 wiz Exp $ */
2 /* $KAME: parser.c,v 1.16 2002/02/20 10:40:39 kjc Exp $ */
4 * Copyright (C) 1999-2002
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>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
46 #include <altq/altq.h>
47 #include <altq/altq_cdnr.h>
48 #include <altq/altq_red.h>
49 #include <altq/altq_rio.h>
53 static int is_qdisc_name(const char *);
54 static int qdisc_interface_parser(const char *, const char *, int, char **);
55 static int qdisc_class_parser(const char *, const char *, const char *,
56 const char *, int, char **);
57 static int next_word(char **, char *);
59 static int get_ifname(char **, char **);
60 static int get_addr(char **, struct in_addr
*, struct in_addr
*);
61 static int get_port(const char *, u_int16_t
*);
62 static int get_proto(const char *, int *);
63 static int get_fltr_opts(char **, char *, size_t, int *);
64 static int interface_parser(char *);
65 static int class_parser(char *) ;
66 static int filter_parser(char *);
68 static int filter6_parser(char *);
69 static int get_ip6addr(char **, struct in6_addr
*, struct in6_addr
*);
71 static int ctl_parser(char *);
72 static int delete_parser(char *);
73 static int red_parser(char *);
74 static int rio_parser(char *);
75 static int conditioner_parser(char *);
76 static int tc_action_parser(char *, char **, struct tc_action
*);
81 #define MAX_ACTIONS 16
84 #define MAX(a,b) (((a)>(b))?(a):(b))
87 #define MIN(a,b) (((a)<(b))?(a):(b))
89 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
94 static char curifname
[IFNAMSIZ
];
95 static struct if_nameindex
*if_namelist
= NULL
;
99 int (*parser
)(char *);
103 {"help", NULL
, "help"},
104 {"quit", NULL
, "quit"},
105 {"interface", interface_parser
, "interface if_name [bandwidth bps] [cbq|hfsc]"},
106 {"class", class_parser
, "class discipline if_name class_name [parent]"},
107 {"filter", filter_parser
, "filter if_name class_name [name filt_name] dst [netmask #] dport src [netmask #] sport proto [tos # [tosmask #] [gpi #] [dontwarn]"},
108 {"altq", ctl_parser
, "altq if_name {enable|disable}"},
109 {"delete", delete_parser
, "delete if_name class_name [filter_name]"},
111 {"filter6", filter6_parser
, "filter6 if_name class_name [name filt_name] dst[/prefix] dport src[/prefix] sport proto [flowlabel #][tclass # [tclassmask #]][gpi #] [dontwarn]"},
113 {"red", red_parser
, "red th_min th_max inv_pmax"},
114 {"rio", rio_parser
, "rio low_th_min low_th_max low_inv_pmax med_th_min med_th_max med_inv_pmax high_th_min high_th_max high_inv_pmax"},
115 {"conditioner", conditioner_parser
, "conditioner if_name cdnr_name <tc_action>"},
116 {"debug", NULL
, "debug"},
117 {NULL
, NULL
, NULL
} /* termination */
121 * read one line from the specified stream. if it's a command,
122 * execute the command.
123 * returns 1 if OK, 0 if error or EOF.
128 char cmd_line
[MAX_LINE
], cmd
[MAX_WORD
], *cp
;
133 * read a line from the stream and make it a null-terminated string
137 if (fgets(cp
, &cmd_line
[MAX_LINE
] - cp
, fp
) == NULL
)
142 /* null-terminate the line */
143 if ((len
= strlen(cmd_line
)) > 0) {
144 cp
= cmd_line
+ len
- 1;
146 /* if escaped newline, read next line */
147 if (len
> 1 && *(cp
- 1) == '\\')
150 } else if (!feof(fp
))
151 err(1, "LINE %d too long!", line_no
);
154 if ((cp
= strchr(cmd_line
, '#')) != NULL
)
158 if ((len
= next_word(&cp
, cmd
)) == 0)
159 /* no command in this line */
162 /* fnind the corresponding parser */
164 for (tp
= cmd_tab
; tp
->cmd
!= NULL
; tp
++)
165 if (strncmp(cmd
, tp
->cmd
, len
) == 0)
168 if (tp
->cmd
== NULL
) {
170 printf(" ?? %s\n", cmd
);
173 LOG(LOG_ERR
, 0, "unknown command: %s", cmd
);
177 if (tp
->parser
!= NULL
)
178 rval
= (*tp
->parser
)(cp
);
180 /* handle other commands */
181 if (strcmp(tp
->cmd
, "quit") == 0)
183 else if (strcmp(tp
->cmd
, "help") == 0 ||
184 strcmp(tp
->cmd
, "?") == 0) {
185 for (tp
= cmd_tab
; tp
->cmd
!= NULL
; tp
++)
186 printf("%s\n", tp
->help
);
188 } else if (strcmp(tp
->cmd
, "debug") == 0) {
189 if (m_debug
& DEBUG_ALTQ
) {
190 /* turn off verbose */
192 m_debug
&= ~DEBUG_ALTQ
;
194 /* turn on verbose */
196 m_debug
|= DEBUG_ALTQ
;
205 is_qdisc_name(const char *qname
)
207 struct qdisc_parser
*qp
;
209 for (qp
= qdisc_parser
; qp
->qname
!= NULL
; qp
++)
210 if (strncmp(qp
->qname
, qname
, strlen(qp
->qname
)) == 0)
216 qdisc_interface_parser(const char * qname
, const char *ifname
,
217 int argc
, char **argv
)
219 struct qdisc_parser
*qp
;
221 for (qp
= qdisc_parser
; qp
->qname
!= NULL
; qp
++)
222 if (strncmp(qp
->qname
, qname
, strlen(qp
->qname
)) == 0)
223 return (*qp
->interface_parser
)(ifname
, argc
, argv
);
228 qdisc_class_parser(const char *qname
, const char *ifname
,
229 const char *class_name
, const char *parent_name
,
230 int argc
, char **argv
)
232 struct qdisc_parser
*qp
;
233 struct ifinfo
*ifinfo
;
235 for (qp
= qdisc_parser
; qp
->qname
!= NULL
; qp
++)
236 if (strncmp(qp
->qname
, qname
, strlen(qp
->qname
)) == 0) {
237 if (qp
->class_parser
== NULL
) {
239 "class can't be specified for %s", qp
->qname
);
242 if ((ifinfo
= ifname2ifinfo(ifname
)) == NULL
) {
243 LOG(LOG_ERR
, 0, "no such interface");
246 if (strncmp(ifinfo
->qdisc
->qname
, qname
,
247 strlen(ifinfo
->qdisc
->qname
)) != 0) {
249 "qname doesn't match the interface");
252 return (*qp
->class_parser
)(ifname
, class_name
,
253 parent_name
, argc
, argv
);
259 * read the config file
267 if (if_namelist
!= NULL
)
268 if_freenameindex(if_namelist
);
269 if_namelist
= if_nameindex();
272 LOG(LOG_INFO
, 0, "ALTQ config file is %s", altqconfigfile
);
274 fp
= fopen(altqconfigfile
, "r");
276 LOG(LOG_ERR
, errno
, "can't open %s", altqconfigfile
, 0);
277 return (QOPERR_INVAL
);
282 rval
= do_command(fp
);
285 LOG(LOG_ERR
, 0, "Error in %s, line %d. config failed.",
286 altqconfigfile
, line_no
);
287 (void) qcmd_destroyall();
298 next_word(char **cpp
, char *b
)
304 while (*cp
== ' ' || *cp
== '\t')
306 for (i
= 0; i
< MAX_WORD
- 1; i
++) {
307 if (*cp
== ' ' || *cp
== '\t' || *cp
== '\n' || *cp
== '\0')
323 get_ifindex(const char *ifname
)
325 struct if_nameindex
*ifnp
;
327 for (ifnp
= if_namelist
; ifnp
->if_name
!= NULL
; ifnp
++)
328 if (strcmp(ifname
, ifnp
->if_name
) == 0)
329 return (ifnp
->if_index
);
334 get_ifname(char **cpp
, char **ifnamep
)
336 char w
[MAX_WORD
], *ocp
;
337 struct if_nameindex
*ifnp
;
340 if (next_word(&ocp
, w
) && if_namelist
!= NULL
)
341 for (ifnp
= if_namelist
; ifnp
->if_name
!= NULL
; ifnp
++)
342 if (strcmp(w
, ifnp
->if_name
) == 0) {
343 /* if_name found. advance the word pointer */
345 strlcpy(curifname
, w
, sizeof(curifname
));
346 *ifnamep
= curifname
;
350 /* this is not interface name. use one in the context. */
351 if (curifname
[0] == '\0')
353 *ifnamep
= curifname
;
357 /* set address and netmask in network byte order */
359 get_addr(char **cpp
, struct in_addr
*addr
, struct in_addr
*mask
)
361 char w
[MAX_WORD
], *ocp
;
365 mask
->s_addr
= 0xffffffff;
367 if (!next_word(cpp
, w
))
370 if (inet_aton((char *)w
, &tmp
) != 1) {
371 /* try gethostbyname */
374 if ((h
= gethostbyname(w
)) == NULL
||
375 h
->h_addrtype
!= AF_INET
|| h
->h_length
!= 4)
377 bcopy(h
->h_addr
, &tmp
, (size_t)h
->h_length
);
379 addr
->s_addr
= tmp
.s_addr
;
381 /* check if netmask option is present */
383 if (next_word(&ocp
, w
) && EQUAL(w
, "netmask")) {
384 if (!next_word(&ocp
, w
))
386 if (inet_aton((char *)w
, (struct in_addr
*)&tmp
) != 1)
389 mask
->s_addr
= tmp
.s_addr
;
393 /* no netmask option */
397 /* returns service number in network byte order */
399 get_port(const char *name
, u_int16_t
*port_no
)
404 if (isdigit((unsigned char)name
[0])) {
405 num
= (u_int16_t
)strtol(name
, NULL
, 0);
406 *port_no
= htons(num
);
410 if ((s
= getservbyname(name
, 0)) == NULL
)
413 *port_no
= (u_int16_t
)s
->s_port
;
418 get_proto(const char *name
, int *proto_no
)
422 if (isdigit((unsigned char)name
[0])) {
423 *proto_no
= (int)strtol(name
, NULL
, 0);
427 if ((p
= getprotobyname(name
)) == NULL
)
430 *proto_no
= p
->p_proto
;
435 get_fltr_opts(char **cpp
, char *fltr_name
, size_t len
, int *ruleno
)
437 char w
[MAX_WORD
], *ocp
;
440 while (next_word(&ocp
, w
)) {
441 if (EQUAL(w
, "name")) {
442 if (!next_word(&ocp
, w
))
444 strlcpy(fltr_name
, w
, len
);
446 } else if (EQUAL(w
, "ruleno")) {
447 if (!next_word(&ocp
, w
))
449 *ruleno
= (int)strtol(w
, NULL
, 0);
458 #define DISCIPLINE_NONE 0
461 interface_parser(char *cmdbuf
)
463 char w
[MAX_WORD
], *ap
, *cp
= cmdbuf
;
464 char *ifname
, *argv
[MAX_ARGS
], qdisc_name
[MAX_WORD
];
467 if (!get_ifname(&cp
, &ifname
)) {
468 LOG(LOG_ERR
, 0, "missing interface name");
472 /* create argment list & look for scheduling discipline options. */
473 snprintf(qdisc_name
, sizeof qdisc_name
, "null");
476 while (next_word(&cp
, ap
)) {
477 if (is_qdisc_name(ap
))
478 strlcpy(qdisc_name
, ap
, sizeof qdisc_name
);
481 ap
+= strlen(ap
) + 1;
483 if (argc
>= MAX_ARGS
) {
484 LOG(LOG_ERR
, 0, "too many args");
489 return qdisc_interface_parser(qdisc_name
, ifname
, argc
, argv
);
494 class_parser(char *cmdbuf
)
496 char w
[MAX_WORD
], *cp
= cmdbuf
;
497 char *ifname
, qdisc_name
[MAX_WORD
];
498 char class_name
[MAX_WORD
], parent_name
[MAX_WORD
];
499 char *clname
= class_name
;
501 char *argv
[MAX_ARGS
], *ap
;
504 /* get scheduling class */
505 if (!next_word(&cp
, qdisc_name
)) {
506 LOG(LOG_ERR
, 0, "missing discipline");
509 if (!is_qdisc_name(qdisc_name
)) {
510 LOG(LOG_ERR
, 0, "unknown discipline '%s'", qdisc_name
);
514 /* get interface name */
515 if (!get_ifname(&cp
, &ifname
)) {
516 LOG(LOG_ERR
, 0, "missing interface name");
521 if (!next_word(&cp
, class_name
)) {
522 LOG(LOG_ERR
, 0, "missing class name");
526 /* get parent name */
527 if (!next_word(&cp
, parent_name
)) {
528 LOG(LOG_ERR
, 0, "missing parent class");
531 if (!EQUAL(parent_name
, "null") && !EQUAL(parent_name
, "NULL"))
532 parent
= parent_name
;
538 while (next_word(&cp
, ap
)) {
540 ap
+= strlen(ap
) + 1;
542 if (argc
>= MAX_ARGS
) {
543 LOG(LOG_ERR
, 0, "too many args");
548 return qdisc_class_parser(qdisc_name
, ifname
, clname
, parent
,
553 filter_parser(char *cmdbuf
)
555 char w
[MAX_WORD
], *cp
= cmdbuf
;
556 char *ifname
, class_name
[MAX_WORD
], fltr_name
[MAX_WORD
];
558 struct flow_filter sfilt
;
565 memset(&sfilt
, 0, sizeof(sfilt
));
566 sfilt
.ff_flow
.fi_family
= AF_INET
;
568 if (!get_ifname(&cp
, &ifname
)) {
569 LOG(LOG_ERR
, 0, "missing interface name in filter command");
573 if (!next_word(&cp
, class_name
)) {
574 LOG(LOG_ERR
, 0, "missing class name in filter command");
580 if (!get_fltr_opts(&cp
, &fltr_name
[0], sizeof(fltr_name
), &ruleno
)) {
581 LOG(LOG_ERR
, 0, "bad filter option");
584 if (fltr_name
[0] != '\0')
586 sfilt
.ff_ruleno
= ruleno
;
588 /* get filter destination Address */
589 if (!get_addr(&cp
, &sfilt
.ff_flow
.fi_dst
, &sfilt
.ff_mask
.mask_dst
)) {
590 LOG(LOG_ERR
, 0, "bad filter destination address");
594 /* get filter destination port */
595 if (!next_word(&cp
, w
)) {
596 LOG(LOG_ERR
, 0, "missing filter destination port");
599 if (!get_port(w
, &sfilt
.ff_flow
.fi_dport
)) {
600 LOG(LOG_ERR
, 0, "bad filter destination port");
604 /* get filter source address */
605 if (!get_addr(&cp
, &sfilt
.ff_flow
.fi_src
, &sfilt
.ff_mask
.mask_src
)) {
606 LOG(LOG_ERR
, 0, "bad filter source address");
610 /* get filter source port */
611 if (!next_word(&cp
, w
)) {
612 LOG(LOG_ERR
, 0, "missing filter source port");
615 if (!get_port(w
, &sfilt
.ff_flow
.fi_sport
)) {
616 LOG(LOG_ERR
, 0, "bad filter source port");
620 /* get filter protocol id */
621 if (!next_word(&cp
, w
)) {
622 LOG(LOG_ERR
, 0, "missing filter protocol");
625 if (!get_proto(w
, &protocol
)) {
626 LOG(LOG_ERR
, 0, "bad protocol");
629 sfilt
.ff_flow
.fi_proto
= protocol
;
631 while (next_word(&cp
, w
)) {
632 if (EQUAL(w
, "tos")) {
636 if (next_word(&cp
, w
)) {
637 tos
= (u_char
)strtol(w
, NULL
, 0);
638 if (next_word(&cp
, w
)) {
639 if (EQUAL(w
, "tosmask")) {
641 tosmask
= (u_char
)strtol(w
, NULL
, 0);
645 sfilt
.ff_flow
.fi_tos
= tos
;
646 sfilt
.ff_mask
.mask_tos
= tosmask
;
647 } else if (EQUAL(w
, "gpi")) {
648 if (next_word(&cp
, w
)) {
649 sfilt
.ff_flow
.fi_gpi
=
650 (u_int32_t
)strtoul(w
, NULL
, 0);
651 sfilt
.ff_flow
.fi_gpi
=
652 htonl(sfilt
.ff_flow
.fi_gpi
);
654 } else if (EQUAL(w
, "dontwarn"))
661 filter_dontwarn
= dontwarn
; /* XXX */
662 error
= qcmd_add_filter(ifname
, class_name
, flname
, &sfilt
);
663 filter_dontwarn
= 0; /* XXX */
666 "can't add filter to class '%s' on interface '%s'",
675 filter6_parser(char *cmdbuf
)
677 char w
[MAX_WORD
], *cp
= cmdbuf
;
678 char *ifname
, class_name
[MAX_WORD
], fltr_name
[MAX_WORD
];
680 struct flow_filter6 sfilt
;
682 u_char tclass
, tclassmask
;
687 memset(&sfilt
, 0, sizeof(sfilt
));
688 sfilt
.ff_flow6
.fi6_family
= AF_INET6
;
690 if (!get_ifname(&cp
, &ifname
)) {
691 LOG(LOG_ERR
, 0, "missing interface name");
695 if (!next_word(&cp
, class_name
)) {
696 LOG(LOG_ERR
, 0, "missing class name");
702 if (!get_fltr_opts(&cp
, &fltr_name
[0], sizeof(fltr_name
), &ruleno
)) {
703 LOG(LOG_ERR
, 0, "bad filter option");
706 if (fltr_name
[0] != '\0')
708 sfilt
.ff_ruleno
= ruleno
;
710 /* get filter destination address */
711 if (!get_ip6addr(&cp
, &sfilt
.ff_flow6
.fi6_dst
,
712 &sfilt
.ff_mask6
.mask6_dst
)) {
713 LOG(LOG_ERR
, 0, "bad destination address");
717 /* get filter destination port */
718 if (!next_word(&cp
, w
)) {
719 LOG(LOG_ERR
, 0, "missing filter destination port");
722 if (!get_port(w
, &sfilt
.ff_flow6
.fi6_dport
)) {
723 LOG(LOG_ERR
, 0, "bad filter destination port");
727 /* get filter source address */
728 if (!get_ip6addr(&cp
, &sfilt
.ff_flow6
.fi6_src
,
729 &sfilt
.ff_mask6
.mask6_src
)) {
730 LOG(LOG_ERR
, 0, "bad source address");
734 /* get filter source port */
735 if (!next_word(&cp
, w
)) {
736 LOG(LOG_ERR
, 0, "missing filter source port");
739 if (!get_port(w
, &sfilt
.ff_flow6
.fi6_sport
)) {
740 LOG(LOG_ERR
, 0, "bad filter source port");
744 /* get filter protocol id */
745 if (!next_word(&cp
, w
)) {
746 LOG(LOG_ERR
, 0, "missing filter protocol");
749 if (!get_proto(w
, &protocol
)) {
750 LOG(LOG_ERR
, 0, "bad protocol");
753 sfilt
.ff_flow6
.fi6_proto
= protocol
;
755 while (next_word(&cp
, w
)) {
756 if (EQUAL(w
, "tclass")) {
760 if (next_word(&cp
, w
)) {
761 tclass
= (u_char
)strtol(w
, NULL
, 0);
762 if (next_word(&cp
, w
)) {
763 if (EQUAL(w
, "tclassmask")) {
766 (u_char
)strtol(w
, NULL
, 0);
770 sfilt
.ff_flow6
.fi6_tclass
= tclass
;
771 sfilt
.ff_mask6
.mask6_tclass
= tclassmask
;
772 } else if (EQUAL(w
, "gpi")) {
773 if (next_word(&cp
, w
)) {
774 sfilt
.ff_flow6
.fi6_gpi
=
775 (u_int32_t
)strtoul(w
, NULL
, 0);
776 sfilt
.ff_flow6
.fi6_gpi
=
777 htonl(sfilt
.ff_flow6
.fi6_gpi
);
779 } else if (EQUAL(w
, "flowlabel")) {
780 if (next_word(&cp
, w
)) {
781 sfilt
.ff_flow6
.fi6_flowlabel
=
782 (u_int32_t
)strtoul(w
, NULL
, 0) & 0x000fffff;
783 sfilt
.ff_flow6
.fi6_flowlabel
=
784 htonl(sfilt
.ff_flow6
.fi6_flowlabel
);
786 } else if (EQUAL(w
, "dontwarn"))
793 filter_dontwarn
= dontwarn
; /* XXX */
794 ret
= qcmd_add_filter(ifname
, class_name
, flname
,
795 (struct flow_filter
*)&sfilt
);
796 filter_dontwarn
= 0; /* XXX */
799 "can't add filter to class '%s' on interface '%s'",
808 get_ip6addr(char **cpp
, struct in6_addr
*addr
, struct in6_addr
*mask
)
810 char w
[MAX_WORD
], *prefix
;
814 *addr
= in6addr_any
; /* set all 0 */
815 *mask
= in6addr_any
; /* set all 0 */
817 if (!next_word(cpp
, w
))
821 /* abbreviation of a wildcard (::0) */
824 if ((prefix
= strchr(w
, '/')) != NULL
) {
825 /* address has prefix length */
829 if (inet_pton(AF_INET6
, w
, addr
) != 1)
832 if (IN6_IS_ADDR_UNSPECIFIED(addr
) && prefix
== NULL
)
836 /* convert address prefix length to address mask */
837 if (prefix
!= NULL
) {
838 len
= (int)strtol(prefix
, NULL
, 0);
839 if ((len
< 0) || (len
> 128))
841 for (cp
= (u_char
*)mask
; len
> 7; len
-= 8)
844 *cp
= (0xff << (8 - len
)) & 0xff;
846 IN6ADDR32(addr
, 0) &= IN6ADDR32(mask
, 0);
847 IN6ADDR32(addr
, 1) &= IN6ADDR32(mask
, 1);
848 IN6ADDR32(addr
, 2) &= IN6ADDR32(mask
, 2);
849 IN6ADDR32(addr
, 3) &= IN6ADDR32(mask
, 3);
852 memset(mask
, 0xff, sizeof(struct in6_addr
));
860 ctl_parser(char *cmdbuf
)
862 char w
[MAX_WORD
], *cp
= cmdbuf
;
867 if (!get_ifname(&cp
, &ifname
)) {
868 printf("missing interface name in %s, line %d",
869 altqconfigfile
, line_no
);
873 if (!next_word(&cp
, w
)) {
874 state
= is_q_enabled(ifname
);
875 printf("altq %s on %s\n",
876 state
? "enabled" : "disabled", ifname
);
880 if (EQUAL(w
, "enable")) {
881 rval
= qcmd_enable(ifname
);
882 printf("altq %s on %s\n",
883 (rval
== 0) ? "enabled" : "enable failed!", ifname
);
884 } else if (EQUAL(w
, "disable")) {
885 rval
= qcmd_disable(ifname
);
886 printf("altq %s on %s\n",
887 (rval
== 0) ? "disabled" : "disable failed!", ifname
);
888 } else if (EQUAL(w
, "reload")) {
889 printf("reinitializing altq...\n");
898 delete_parser(char *cmdbuf
)
901 char *ifname
, class_name
[MAX_WORD
], filter_name
[MAX_WORD
];
904 if (!get_ifname(&cp
, &ifname
)) {
905 LOG(LOG_ERR
, 0, "missing interface name");
909 if (!next_word(&cp
, class_name
)) {
910 LOG(LOG_ERR
, 0, "missing class name");
914 /* check if filter is specified */
915 if (next_word(&cp
, filter_name
)) {
916 ret
= qcmd_delete_filter(ifname
, class_name
, filter_name
);
919 "can't delete filter '%s' on interface '%s'",
920 filter_name
, ifname
);
926 ret
= qcmd_delete_class(ifname
, class_name
);
929 "can't delete class '%s' on interface '%s'",
938 red_parser(char *cmdbuf
)
940 char w
[MAX_WORD
], *cp
= cmdbuf
;
941 int th_min
, th_max
, inv_pmax
;
943 if (!next_word(&cp
, w
))
945 th_min
= (int)strtol(w
, NULL
, 0);
947 if (!next_word(&cp
, w
))
949 th_max
= (int)strtol(w
, NULL
, 0);
951 if (!next_word(&cp
, w
))
953 inv_pmax
= (int)strtol(w
, NULL
, 0);
955 if (qop_red_set_defaults(th_min
, th_max
, inv_pmax
) != 0) {
956 LOG(LOG_ERR
, 0, "can't set red default parameters");
963 LOG(LOG_ERR
, 0, "bad red parameter");
968 rio_parser(char *cmdbuf
)
970 char w
[MAX_WORD
], *cp
= cmdbuf
;
972 struct redparams params
[RIO_NDROPPREC
];
974 for (i
= 0; i
< RIO_NDROPPREC
; i
++) {
975 if (!next_word(&cp
, w
))
977 params
[i
].th_min
= (int)strtol(w
, NULL
, 0);
979 if (!next_word(&cp
, w
))
981 params
[i
].th_max
= (int)strtol(w
, NULL
, 0);
983 if (!next_word(&cp
, w
))
985 params
[i
].inv_pmax
= (int)strtol(w
, NULL
, 0);
988 if (qop_rio_set_defaults(¶ms
[0]) != 0) {
989 LOG(LOG_ERR
, 0, "can't set rio default parameters");
996 LOG(LOG_ERR
, 0, "bad rio parameter");
1001 conditioner_parser(char *cmdbuf
)
1003 char cdnr_name
[MAX_WORD
], *cp
= cmdbuf
;
1005 struct tc_action action
[MAX_ACTIONS
];
1007 if (!get_ifname(&cp
, &ifname
)) {
1008 LOG(LOG_ERR
, 0, "missing interface name");
1012 /* get conditioner name */
1013 if (!next_word(&cp
, cdnr_name
)) {
1014 LOG(LOG_ERR
, 0, "missing cdnr name");
1018 if (tc_action_parser(ifname
, &cp
, &action
[0]) == 0)
1021 if (qcmd_cdnr_add_element(NULL
, ifname
, cdnr_name
, &action
[0]) != 0)
1027 * recursively parse '<'tc_action'>'
1028 * note that array "action" grows during recursive parse.
1031 tc_action_parser(char *ifname
, char **cpp
, struct tc_action
*action
)
1033 char *cp
, *start
, *end
;
1034 char type
[MAX_WORD
], w
[MAX_WORD
];
1036 struct tb_profile profile
[2];
1039 * find a possibly nested pair of '<' and '>',
1040 * make them pointed by 'start' and 'end'.
1042 start
= strchr(*cpp
, '<');
1043 if (start
== NULL
) {
1044 LOG(LOG_ERR
, 0, "conditioner action missing");
1050 end
= strpbrk(cp
, "<>");
1053 "conditioner action delimiter mismatch");
1058 else if (*end
== '>')
1061 } while (depth
> 0);
1066 if (IsDebug(DEBUG_ALTQ
)) {
1067 printf("tc_action_parser: [%s]\n", cp
);
1070 if (!next_word(&cp
, type
)) {
1071 LOG(LOG_ERR
, 0, "missing conditioner action type");
1076 * action type specific process
1078 if (EQUAL(type
, "conditioner")) {
1079 if (!next_word(&cp
, w
)) {
1081 "missing conditioner name");
1084 action
->tca_code
= TCACODE_HANDLE
;
1085 action
->tca_handle
= cdnr_name2handle(ifname
, w
);
1086 if (action
->tca_handle
== CDNR_NULL_HANDLE
) {
1088 "wrong conditioner name %s", w
);
1091 } else if (EQUAL(type
, "pass")) {
1092 action
->tca_code
= TCACODE_PASS
;
1093 } else if (EQUAL(type
, "drop")) {
1094 action
->tca_code
= TCACODE_DROP
;
1095 } else if (EQUAL(type
, "mark")) {
1096 if (!next_word(&cp
, w
)) {
1097 LOG(LOG_ERR
, 0, "missing dscp");
1100 action
->tca_code
= TCACODE_MARK
;
1101 action
->tca_dscp
= (u_int8_t
)strtol(w
, NULL
, 0);
1102 } else if (EQUAL(type
, "tbmeter")) {
1103 if (!next_word(&cp
, w
)) {
1104 LOG(LOG_ERR
, 0, "missing tb profile");
1107 profile
[0].rate
= atobps(w
);
1108 if (!next_word(&cp
, w
)) {
1109 LOG(LOG_ERR
, 0, "missing tb profile");
1112 profile
[0].depth
= atobytes(w
);
1113 if (tc_action_parser(ifname
, &cp
, &action
[1]) == 0)
1115 if (tc_action_parser(ifname
, &cp
, &action
[2]) == 0)
1118 if (qcmd_cdnr_add_tbmeter(action
, ifname
, NULL
, &profile
[0],
1119 &action
[1], &action
[2]) != 0)
1121 } else if (EQUAL(type
, "trtcm")) {
1122 int coloraware
= 0; /* default is color-blind */
1124 for (i
=0; i
<2; i
++) {
1125 if (!next_word(&cp
, w
)) {
1126 LOG(LOG_ERR
, 0, "missing tb profile");
1129 profile
[i
].rate
= atobps(w
);
1130 if (!next_word(&cp
, w
)) {
1131 LOG(LOG_ERR
, 0, "missing tb profile");
1134 profile
[i
].depth
= atobytes(w
);
1136 if (tc_action_parser(ifname
, &cp
, &action
[1]) == 0)
1138 if (tc_action_parser(ifname
, &cp
, &action
[2]) == 0)
1140 if (tc_action_parser(ifname
, &cp
, &action
[3]) == 0)
1142 if (next_word(&cp
, w
)) {
1143 if (EQUAL(w
, "coloraware"))
1145 else if (EQUAL(w
, "colorblind"))
1149 if (qcmd_cdnr_add_trtcm(action
, ifname
, NULL
,
1150 &profile
[0], &profile
[1],
1151 &action
[1], &action
[2], &action
[3],
1154 } else if (EQUAL(type
, "tswtcm")) {
1155 u_int32_t cmtd_rate
, peak_rate
, avg_interval
;
1157 if (!next_word(&cp
, w
)) {
1158 LOG(LOG_ERR
, 0, "missing cmtd rate");
1161 cmtd_rate
= atobps(w
);
1163 if (!next_word(&cp
, w
)) {
1164 LOG(LOG_ERR
, 0, "missing peak rate");
1167 peak_rate
= atobps(w
);
1169 if (!next_word(&cp
, w
)) {
1170 LOG(LOG_ERR
, 0, "missing avg interval");
1173 avg_interval
= (u_int32_t
)strtoul(w
, NULL
, 0);
1175 if (tc_action_parser(ifname
, &cp
, &action
[1]) == 0)
1177 if (tc_action_parser(ifname
, &cp
, &action
[2]) == 0)
1179 if (tc_action_parser(ifname
, &cp
, &action
[3]) == 0)
1182 if (qcmd_cdnr_add_tswtcm(action
, ifname
, NULL
,
1183 cmtd_rate
, peak_rate
, avg_interval
,
1184 &action
[1], &action
[2], &action
[3])
1188 LOG(LOG_ERR
, 0, "unknown action type %s");
1192 *end
= '>'; /* restore the end delimiter */