1 /* $NetBSD: qop_rio.c,v 1.4 2001/08/22 08:52:37 itojun Exp $ */
2 /* $KAME: qop_rio.c,v 1.6 2001/12/03 08:20:56 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>
50 #include <altq/altq_rio.h>
54 static int rio_attach(struct ifinfo
*);
55 static int rio_detach(struct ifinfo
*);
56 static int rio_enable(struct ifinfo
*);
57 static int rio_disable(struct ifinfo
*);
59 #define RIO_DEVICE "/dev/altq/rio"
61 static int rio_fd
= -1;
62 static int rio_refcount
= 0;
64 static struct qdisc_ops rio_qdisc
= {
73 NULL
, /* modify class */
74 NULL
, /* delete class */
75 NULL
, /* add filter */
76 NULL
/* delete filter */
82 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
85 rio_interface_parser(const char *ifname
, int argc
, char **argv
)
87 u_int bandwidth
= 100000000; /* 100Mbps */
89 int weight
= 0; /* 0: use default */
90 int lo_inv_pmax
= 0; /* 0: use default */
91 int lo_th_min
= 0; /* 0: use default */
92 int lo_th_max
= 0; /* 0: use default */
93 int med_inv_pmax
= 0; /* 0: use default */
94 int med_th_min
= 0; /* 0: use default */
95 int med_th_max
= 0; /* 0: use default */
96 int hi_inv_pmax
= 0; /* 0: use default */
97 int hi_th_min
= 0; /* 0: use default */
98 int hi_th_max
= 0; /* 0: use default */
102 int packet_size
= 1000;
108 if (EQUAL(*argv
, "bandwidth")) {
111 bandwidth
= atobps(*argv
);
112 } else if (EQUAL(*argv
, "tbrsize")) {
115 tbrsize
= atobytes(*argv
);
116 } else if (EQUAL(*argv
, "packetsize")) {
119 packet_size
= atobytes(*argv
);
120 } else if (EQUAL(*argv
, "weight")) {
123 weight
= (int)strtol(*argv
, NULL
, 0);
124 } else if (EQUAL(*argv
, "qlimit")) {
127 qlimit
= (int)strtol(*argv
, NULL
, 0);
128 } else if (EQUAL(*argv
, "lo_thmin")) {
131 lo_th_min
= (int)strtol(*argv
, NULL
, 0);
132 } else if (EQUAL(*argv
, "lo_thmax")) {
135 lo_th_max
= (int)strtol(*argv
, NULL
, 0);
136 } else if (EQUAL(*argv
, "lo_invpmax")) {
139 lo_inv_pmax
= (int)strtol(*argv
, NULL
, 0);
140 } else if (EQUAL(*argv
, "med_thmin")) {
143 med_th_min
= (int)strtol(*argv
, NULL
, 0);
144 } else if (EQUAL(*argv
, "med_thmax")) {
147 med_th_max
= (int)strtol(*argv
, NULL
, 0);
148 } else if (EQUAL(*argv
, "med_invpmax")) {
151 med_inv_pmax
= (int)strtol(*argv
, NULL
, 0);
152 } else if (EQUAL(*argv
, "hi_thmin")) {
155 hi_th_min
= (int)strtol(*argv
, NULL
, 0);
156 } else if (EQUAL(*argv
, "hi_thmax")) {
159 hi_th_max
= (int)strtol(*argv
, NULL
, 0);
160 } else if (EQUAL(*argv
, "hi_invpmax")) {
163 hi_inv_pmax
= (int)strtol(*argv
, NULL
, 0);
164 } else if (EQUAL(*argv
, "rio")) {
166 } else if (EQUAL(*argv
, "ecn")) {
169 LOG(LOG_ERR
, 0, "Unknown keyword '%s'", *argv
);
175 if (qcmd_tbr_register(ifname
, bandwidth
, tbrsize
) != 0)
178 pkttime
= packet_size
* 8 * 1000 / (bandwidth
/ 1000);
180 /* check if weight is power of 2 */
184 for (i
= 0; w
> 1; i
++)
188 LOG(LOG_ERR
, 0, "weight %d: should be power of 2",
194 if (qcmd_rio_add_if(ifname
, bandwidth
, weight
,
195 lo_inv_pmax
, lo_th_min
, lo_th_max
,
196 med_inv_pmax
, med_th_min
, med_th_max
,
197 hi_inv_pmax
, hi_th_min
, hi_th_max
,
198 qlimit
, pkttime
, flags
) != 0)
207 qcmd_rio_add_if(const char *ifname
, u_int bandwidth
, int weight
,
208 int lo_inv_pmax
, int lo_th_min
, int lo_th_max
,
209 int med_inv_pmax
, int med_th_min
, int med_th_max
,
210 int hi_inv_pmax
, int hi_th_min
, int hi_th_max
,
211 int qlimit
, int pkttime
, int flags
)
213 struct redparams red_params
[RIO_NDROPPREC
];
216 red_params
[0].inv_pmax
= lo_inv_pmax
;
217 red_params
[0].th_min
= lo_th_min
;
218 red_params
[0].th_max
= lo_th_max
;
219 red_params
[1].inv_pmax
= med_inv_pmax
;
220 red_params
[1].th_min
= med_th_min
;
221 red_params
[1].th_max
= med_th_max
;
222 red_params
[2].inv_pmax
= hi_inv_pmax
;
223 red_params
[2].th_min
= hi_th_min
;
224 red_params
[2].th_max
= hi_th_max
;
226 error
= qop_rio_add_if(NULL
, ifname
, bandwidth
, weight
, red_params
,
227 qlimit
, pkttime
, flags
);
229 LOG(LOG_ERR
, errno
, "%s: can't add rio on interface '%s'",
230 qoperror(error
), ifname
);
238 qop_rio_add_if(struct ifinfo
**rp
, const char *ifname
,
239 u_int bandwidth
, int weight
, struct redparams
*red_params
,
240 int qlimit
, int pkttime
, int flags
)
242 struct ifinfo
*ifinfo
= NULL
;
243 struct rio_ifinfo
*rio_ifinfo
;
246 if ((rio_ifinfo
= calloc(1, sizeof(*rio_ifinfo
))) == NULL
)
247 return (QOPERR_NOMEM
);
248 for (i
= 0; i
< RIO_NDROPPREC
; i
++)
249 rio_ifinfo
->red_params
[i
] = red_params
[i
];
250 rio_ifinfo
->weight
= weight
;
251 rio_ifinfo
->qlimit
= qlimit
;
252 rio_ifinfo
->pkttime
= pkttime
;
253 rio_ifinfo
->flags
= flags
;
255 error
= qop_add_if(&ifinfo
, ifname
, bandwidth
,
256 &rio_qdisc
, rio_ifinfo
);
268 * system call interfaces for qdisc_ops
271 rio_attach(struct ifinfo
*ifinfo
)
273 struct rio_interface iface
;
274 struct rio_ifinfo
*rio_ifinfo
;
275 struct rio_conf conf
;
279 (rio_fd
= open(RIO_DEVICE
, O_RDWR
)) < 0 &&
280 (rio_fd
= open_module(RIO_DEVICE
, O_RDWR
)) < 0) {
281 LOG(LOG_ERR
, errno
, "RIO open");
282 return (QOPERR_SYSCALL
);
286 memset(&iface
, 0, sizeof(iface
));
287 strncpy(iface
.rio_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
289 if (ioctl(rio_fd
, RIO_IF_ATTACH
, &iface
) < 0)
290 return (QOPERR_SYSCALL
);
292 /* set rio parameters */
293 rio_ifinfo
= (struct rio_ifinfo
*)ifinfo
->private;
294 memset(&conf
, 0, sizeof(conf
));
295 strncpy(conf
.iface
.rio_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
296 for (i
= 0; i
< RIO_NDROPPREC
; i
++)
297 conf
.q_params
[i
] = rio_ifinfo
->red_params
[i
];
298 conf
.rio_weight
= rio_ifinfo
->weight
;
299 conf
.rio_limit
= rio_ifinfo
->qlimit
;
300 conf
.rio_flags
= rio_ifinfo
->flags
;
301 if (ioctl(rio_fd
, RIO_CONFIG
, &conf
) < 0)
302 return (QOPERR_SYSCALL
);
305 LOG(LOG_INFO
, 0, "rio attached to %s", iface
.rio_ifname
);
311 rio_detach(struct ifinfo
*ifinfo
)
313 struct rio_interface iface
;
315 memset(&iface
, 0, sizeof(iface
));
316 strncpy(iface
.rio_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
318 if (ioctl(rio_fd
, RIO_IF_DETACH
, &iface
) < 0)
319 return (QOPERR_SYSCALL
);
321 if (--rio_refcount
== 0) {
329 rio_enable(struct ifinfo
*ifinfo
)
331 struct rio_interface iface
;
333 memset(&iface
, 0, sizeof(iface
));
334 strncpy(iface
.rio_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
336 if (ioctl(rio_fd
, RIO_ENABLE
, &iface
) < 0)
337 return (QOPERR_SYSCALL
);
342 rio_disable(struct ifinfo
*ifinfo
)
344 struct rio_interface iface
;
346 memset(&iface
, 0, sizeof(iface
));
347 strncpy(iface
.rio_ifname
, ifinfo
->ifname
, IFNAMSIZ
);
349 if (ioctl(rio_fd
, RIO_DISABLE
, &iface
) < 0)
350 return (QOPERR_SYSCALL
);