1 /* $NetBSD: qop_red.c,v 1.4 2001/08/22 08:52:37 itojun Exp $ */
2 /* $KAME: qop_red.c,v 1.6 2001/12/03 08:20:55 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 #include <netinet/in.h>
36 #include <arpa/inet.h>
48 #include <altq/altq.h>
49 #include <altq/altq_red.h>
53 static int red_attach(struct ifinfo
*);
54 static int red_detach(struct ifinfo
*);
55 static int red_enable(struct ifinfo
*);
56 static int red_disable(struct ifinfo
*);
58 #define RED_DEVICE "/dev/altq/red"
60 static int red_fd
= -1;
61 static int red_refcount
= 0;
63 static struct qdisc_ops red_qdisc
= {
72 NULL
, /* modify class */
73 NULL
, /* delete class */
74 NULL
, /* add filter */
75 NULL
/* delete filter */
81 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
84 red_interface_parser(const char *ifname
, int argc
, char **argv
)
86 u_int bandwidth
= 100000000; /* 100Mbps */
88 int weight
= 0; /* 0: use default */
89 int inv_pmax
= 0; /* 0: use default */
90 int th_min
= 0; /* 0: use default */
91 int th_max
= 0; /* 0: use default */
95 int packet_size
= 1000;
101 if (EQUAL(*argv
, "bandwidth")) {
104 bandwidth
= atobps(*argv
);
105 } else if (EQUAL(*argv
, "tbrsize")) {
108 tbrsize
= atobytes(*argv
);
109 } else if (EQUAL(*argv
, "packetsize")) {
112 packet_size
= atobytes(*argv
);
113 } else if (EQUAL(*argv
, "weight")) {
116 weight
= (int)strtol(*argv
, NULL
, 0);
117 } else if (EQUAL(*argv
, "qlimit")) {
120 qlimit
= (int)strtol(*argv
, NULL
, 0);
121 } else if (EQUAL(*argv
, "thmin")) {
124 th_min
= (int)strtol(*argv
, NULL
, 0);
125 } else if (EQUAL(*argv
, "thmax")) {
128 th_max
= (int)strtol(*argv
, NULL
, 0);
129 } else if (EQUAL(*argv
, "invpmax")) {
132 inv_pmax
= (int)strtol(*argv
, NULL
, 0);
133 } else if (EQUAL(*argv
, "red")) {
135 } else if (EQUAL(*argv
, "ecn")) {
137 } else if (EQUAL(*argv
, "flowvalve")) {
138 flags
|= REDF_FLOWVALVE
;
140 LOG(LOG_ERR
, 0, "Unknown keyword '%s'", *argv
);
146 if (qcmd_tbr_register(ifname
, bandwidth
, tbrsize
) != 0)
149 pkttime
= packet_size
* 8 * 1000 / (bandwidth
/ 1000);
151 /* check if weight is power of 2 */
155 for (i
= 0; w
> 1; i
++)
159 LOG(LOG_ERR
, 0, "weight %d: should be power of 2",
165 if (qcmd_red_add_if(ifname
, bandwidth
, weight
, inv_pmax
,
166 th_min
, th_max
, qlimit
, pkttime
, flags
) != 0)
175 qcmd_red_add_if(const char *ifname
, u_int bandwidth
, int weight
,
176 int inv_pmax
, int th_min
, int th_max
, int qlimit
,
177 int pkttime
, int flags
)
181 error
= qop_red_add_if(NULL
, ifname
, bandwidth
, weight
, inv_pmax
,
182 th_min
, th_max
, qlimit
, pkttime
, flags
);
184 LOG(LOG_ERR
, errno
, "%s: can't add red on interface '%s'",
185 qoperror(error
), ifname
);
193 qop_red_add_if(struct ifinfo
**rp
, const char *ifname
,
194 u_int bandwidth
, int weight
, int inv_pmax
, int th_min
,
195 int th_max
, int qlimit
, int pkttime
, int flags
)
197 struct ifinfo
*ifinfo
= NULL
;
198 struct red_ifinfo
*red_ifinfo
;
201 if ((red_ifinfo
= calloc(1, sizeof(*red_ifinfo
))) == NULL
)
202 return (QOPERR_NOMEM
);
203 red_ifinfo
->weight
= weight
;
204 red_ifinfo
->inv_pmax
= inv_pmax
;
205 red_ifinfo
->th_min
= th_min
;
206 red_ifinfo
->th_max
= th_max
;
207 red_ifinfo
->qlimit
= qlimit
;
208 red_ifinfo
->pkttime
= pkttime
;
209 red_ifinfo
->flags
= flags
;
211 error
= qop_add_if(&ifinfo
, ifname
, bandwidth
,
212 &red_qdisc
, red_ifinfo
);
224 * system call interfaces for qdisc_ops
227 red_attach(struct ifinfo
*ifinfo
)
229 struct red_interface iface
;
230 struct red_ifinfo
*red_ifinfo
;
231 struct red_conf conf
;
234 (red_fd
= open(RED_DEVICE
, O_RDWR
)) < 0 &&
235 (red_fd
= open_module(RED_DEVICE
, O_RDWR
)) < 0) {
236 LOG(LOG_ERR
, errno
, "RED open");
237 return (QOPERR_SYSCALL
);
241 memset(&iface
, 0, sizeof(iface
));
242 strncpy(iface
.red_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
244 if (ioctl(red_fd
, RED_IF_ATTACH
, &iface
) < 0)
245 return (QOPERR_SYSCALL
);
247 /* set red parameters */
248 red_ifinfo
= (struct red_ifinfo
*)ifinfo
->private;
249 memset(&conf
, 0, sizeof(conf
));
250 strncpy(conf
.iface
.red_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
251 conf
.red_weight
= red_ifinfo
->weight
;
252 conf
.red_inv_pmax
= red_ifinfo
->inv_pmax
;
253 conf
.red_thmin
= red_ifinfo
->th_min
;
254 conf
.red_thmax
= red_ifinfo
->th_max
;
255 conf
.red_limit
= red_ifinfo
->qlimit
;
256 conf
.red_flags
= red_ifinfo
->flags
;
257 if (ioctl(red_fd
, RED_CONFIG
, &conf
) < 0)
258 return (QOPERR_SYSCALL
);
261 LOG(LOG_INFO
, 0, "red attached to %s", iface
.red_ifname
);
267 red_detach(struct ifinfo
*ifinfo
)
269 struct red_interface iface
;
271 memset(&iface
, 0, sizeof(iface
));
272 strncpy(iface
.red_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
274 if (ioctl(red_fd
, RED_IF_DETACH
, &iface
) < 0)
275 return (QOPERR_SYSCALL
);
277 if (--red_refcount
== 0) {
285 red_enable(struct ifinfo
*ifinfo
)
287 struct red_interface iface
;
289 memset(&iface
, 0, sizeof(iface
));
290 strncpy(iface
.red_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
292 if (ioctl(red_fd
, RED_ENABLE
, &iface
) < 0)
293 return (QOPERR_SYSCALL
);
298 red_disable(struct ifinfo
*ifinfo
)
300 struct red_interface iface
;
302 memset(&iface
, 0, sizeof(iface
));
303 strncpy(iface
.red_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
305 if (ioctl(red_fd
, RED_DISABLE
, &iface
) < 0)
306 return (QOPERR_SYSCALL
);