qop_rio.c revision 1.2 1 /* $KAME: qop_rio.c,v 1.3 2000/10/18 09:15:20 kjc Exp $ */
2 /*
3 * Copyright (C) 1999-2000
4 * Sony Computer Science Laboratories, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/sockio.h>
31 #include <sys/ioctl.h>
32 #include <sys/fcntl.h>
33 #include <net/if.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <stddef.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <syslog.h>
45 #include <netdb.h>
46
47 #include <altq/altq.h>
48 #include <altq/altq_red.h>
49 #include <altq/altq_rio.h>
50 #include "altq_qop.h"
51 #include "qop_rio.h"
52
53 static int rio_attach(struct ifinfo *);
54 static int rio_detach(struct ifinfo *);
55 static int rio_enable(struct ifinfo *);
56 static int rio_disable(struct ifinfo *);
57
58 #define RIO_DEVICE "/dev/altq/rio"
59
60 static int rio_fd = -1;
61 static int rio_refcount = 0;
62
63 static struct qdisc_ops rio_qdisc = {
64 ALTQT_RIO,
65 "rio",
66 rio_attach,
67 rio_detach,
68 NULL, /* clear */
69 rio_enable,
70 rio_disable,
71 NULL, /* add class */
72 NULL, /* modify class */
73 NULL, /* delete class */
74 NULL, /* add filter */
75 NULL /* delete filter */
76 };
77
78 /*
79 * parser interface
80 */
81 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
82
83 int
84 rio_interface_parser(const char *ifname, int argc, char **argv)
85 {
86 u_int bandwidth = 100000000; /* 100Mbps */
87 u_int tbrsize = 0;
88 int weight = 0; /* 0: use default */
89 int lo_inv_pmax = 0; /* 0: use default */
90 int lo_th_min = 0; /* 0: use default */
91 int lo_th_max = 0; /* 0: use default */
92 int med_inv_pmax = 0; /* 0: use default */
93 int med_th_min = 0; /* 0: use default */
94 int med_th_max = 0; /* 0: use default */
95 int hi_inv_pmax = 0; /* 0: use default */
96 int hi_th_min = 0; /* 0: use default */
97 int hi_th_max = 0; /* 0: use default */
98 int qlimit = 60;
99 int pkttime = 0;
100 int flags = 0;
101 int packet_size = 1000;
102
103 /*
104 * process options
105 */
106 while (argc > 0) {
107 if (EQUAL(*argv, "bandwidth")) {
108 argc--; argv++;
109 if (argc > 0)
110 bandwidth = atobps(*argv);
111 } else if (EQUAL(*argv, "tbrsize")) {
112 argc--; argv++;
113 if (argc > 0)
114 tbrsize = atobytes(*argv);
115 } else if (EQUAL(*argv, "packetsize")) {
116 argc--; argv++;
117 if (argc > 0)
118 packet_size = atobytes(*argv);
119 } else if (EQUAL(*argv, "weight")) {
120 argc--; argv++;
121 if (argc > 0)
122 weight = (int)strtol(*argv, NULL, 0);
123 } else if (EQUAL(*argv, "qlimit")) {
124 argc--; argv++;
125 if (argc > 0)
126 qlimit = (int)strtol(*argv, NULL, 0);
127 } else if (EQUAL(*argv, "lo_thmin")) {
128 argc--; argv++;
129 if (argc > 0)
130 lo_th_min = (int)strtol(*argv, NULL, 0);
131 } else if (EQUAL(*argv, "lo_thmax")) {
132 argc--; argv++;
133 if (argc > 0)
134 lo_th_max = (int)strtol(*argv, NULL, 0);
135 } else if (EQUAL(*argv, "lo_invpmax")) {
136 argc--; argv++;
137 if (argc > 0)
138 lo_inv_pmax = (int)strtol(*argv, NULL, 0);
139 } else if (EQUAL(*argv, "med_thmin")) {
140 argc--; argv++;
141 if (argc > 0)
142 med_th_min = (int)strtol(*argv, NULL, 0);
143 } else if (EQUAL(*argv, "med_thmax")) {
144 argc--; argv++;
145 if (argc > 0)
146 med_th_max = (int)strtol(*argv, NULL, 0);
147 } else if (EQUAL(*argv, "med_invpmax")) {
148 argc--; argv++;
149 if (argc > 0)
150 med_inv_pmax = (int)strtol(*argv, NULL, 0);
151 } else if (EQUAL(*argv, "hi_thmin")) {
152 argc--; argv++;
153 if (argc > 0)
154 hi_th_min = (int)strtol(*argv, NULL, 0);
155 } else if (EQUAL(*argv, "hi_thmax")) {
156 argc--; argv++;
157 if (argc > 0)
158 hi_th_max = (int)strtol(*argv, NULL, 0);
159 } else if (EQUAL(*argv, "hi_invpmax")) {
160 argc--; argv++;
161 if (argc > 0)
162 hi_inv_pmax = (int)strtol(*argv, NULL, 0);
163 } else if (EQUAL(*argv, "rio")) {
164 /* just skip */
165 } else if (EQUAL(*argv, "ecn")) {
166 flags |= RIOF_ECN;
167 } else {
168 LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv);
169 return (0);
170 }
171 argc--; argv++;
172 }
173
174 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
175 return (0);
176
177 pkttime = packet_size * 8 * 1000 / (bandwidth / 1000);
178 if (weight != 0) {
179 /* check if weight is power of 2 */
180 int i, w;
181
182 w = weight;
183 for (i = 0; w > 1; i++)
184 w = w >> 1;
185 w = 1 << i;
186 if (weight != w) {
187 LOG(LOG_ERR, 0, "weight %d: should be power of 2",
188 weight);
189 return (0);
190 }
191 }
192
193 if (qcmd_rio_add_if(ifname, bandwidth, weight,
194 lo_inv_pmax, lo_th_min, lo_th_max,
195 med_inv_pmax, med_th_min, med_th_max,
196 hi_inv_pmax, hi_th_min, hi_th_max,
197 qlimit, pkttime, flags) != 0)
198 return (0);
199 return (1);
200 }
201
202 /*
203 * qcmd api
204 */
205 int
206 qcmd_rio_add_if(const char *ifname, u_int bandwidth, int weight,
207 int lo_inv_pmax, int lo_th_min, int lo_th_max,
208 int med_inv_pmax, int med_th_min, int med_th_max,
209 int hi_inv_pmax, int hi_th_min, int hi_th_max,
210 int qlimit, int pkttime, int flags)
211 {
212 struct redparams red_params[RIO_NDROPPREC];
213 int error;
214
215 red_params[0].inv_pmax = lo_inv_pmax;
216 red_params[0].th_min = lo_th_min;
217 red_params[0].th_max = lo_th_max;
218 red_params[1].inv_pmax = med_inv_pmax;
219 red_params[1].th_min = med_th_min;
220 red_params[1].th_max = med_th_max;
221 red_params[2].inv_pmax = hi_inv_pmax;
222 red_params[2].th_min = hi_th_min;
223 red_params[2].th_max = hi_th_max;
224
225 error = qop_rio_add_if(NULL, ifname, bandwidth, weight, red_params,
226 qlimit, pkttime, flags);
227 if (error != 0)
228 LOG(LOG_ERR, errno, "%s: can't add rio on interface '%s'\n",
229 qoperror(error), ifname);
230 return (error);
231 }
232
233 /*
234 * qop api
235 */
236 int
237 qop_rio_add_if(struct ifinfo **rp, const char *ifname,
238 u_int bandwidth, int weight, struct redparams *red_params,
239 int qlimit, int pkttime, int flags)
240 {
241 struct ifinfo *ifinfo = NULL;
242 struct rio_ifinfo *rio_ifinfo;
243 int i, error;
244
245 if ((rio_ifinfo = calloc(1, sizeof(*rio_ifinfo))) == NULL)
246 return (QOPERR_NOMEM);
247 for (i = 0; i < RIO_NDROPPREC; i++)
248 rio_ifinfo->red_params[i] = red_params[i];
249 rio_ifinfo->weight = weight;
250 rio_ifinfo->qlimit = qlimit;
251 rio_ifinfo->pkttime = pkttime;
252 rio_ifinfo->flags = flags;
253
254 error = qop_add_if(&ifinfo, ifname, bandwidth,
255 &rio_qdisc, rio_ifinfo);
256 if (error != 0) {
257 free(rio_ifinfo);
258 return (error);
259 }
260
261 if (rp != NULL)
262 *rp = ifinfo;
263 return (0);
264 }
265
266 /*
267 * system call interfaces for qdisc_ops
268 */
269 static int
270 rio_attach(struct ifinfo *ifinfo)
271 {
272 struct rio_interface iface;
273 struct rio_ifinfo *rio_ifinfo;
274 struct rio_conf conf;
275 int i;
276
277 if (rio_fd < 0 &&
278 (rio_fd = open(RIO_DEVICE, O_RDWR)) < 0 &&
279 (rio_fd = open_module(RIO_DEVICE, O_RDWR)) < 0) {
280 LOG(LOG_ERR, errno, "RIO open\n");
281 return (QOPERR_SYSCALL);
282 }
283
284 rio_refcount++;
285 memset(&iface, 0, sizeof(iface));
286 strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
287
288 if (ioctl(rio_fd, RIO_IF_ATTACH, &iface) < 0)
289 return (QOPERR_SYSCALL);
290
291 /* set rio parameters */
292 rio_ifinfo = (struct rio_ifinfo *)ifinfo->private;
293 memset(&conf, 0, sizeof(conf));
294 strncpy(conf.iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
295 for (i = 0; i < RIO_NDROPPREC; i++)
296 conf.q_params[i] = rio_ifinfo->red_params[i];
297 conf.rio_weight = rio_ifinfo->weight;
298 conf.rio_limit = rio_ifinfo->qlimit;
299 conf.rio_flags = rio_ifinfo->flags;
300 if (ioctl(rio_fd, RIO_CONFIG, &conf) < 0)
301 return (QOPERR_SYSCALL);
302
303 #if 1
304 LOG(LOG_INFO, 0, "rio attached to %s\n", iface.rio_ifname);
305 #endif
306 return (0);
307 }
308
309 static int
310 rio_detach(struct ifinfo *ifinfo)
311 {
312 struct rio_interface iface;
313
314 memset(&iface, 0, sizeof(iface));
315 strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
316
317 if (ioctl(rio_fd, RIO_IF_DETACH, &iface) < 0)
318 return (QOPERR_SYSCALL);
319
320 if (--rio_refcount == 0) {
321 close(rio_fd);
322 rio_fd = -1;
323 }
324 return (0);
325 }
326
327 static int
328 rio_enable(struct ifinfo *ifinfo)
329 {
330 struct rio_interface iface;
331
332 memset(&iface, 0, sizeof(iface));
333 strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
334
335 if (ioctl(rio_fd, RIO_ENABLE, &iface) < 0)
336 return (QOPERR_SYSCALL);
337 return (0);
338 }
339
340 static int
341 rio_disable(struct ifinfo *ifinfo)
342 {
343 struct rio_interface iface;
344
345 memset(&iface, 0, sizeof(iface));
346 strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
347
348 if (ioctl(rio_fd, RIO_DISABLE, &iface) < 0)
349 return (QOPERR_SYSCALL);
350 return (0);
351 }
352