qop_red.c revision 1.1 1 /* $KAME: qop_red.c,v 1.3 2000/10/18 09:15:19 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_qop.h"
50 #include "qop_red.h"
51
52 static int red_attach(struct ifinfo *ifinfo);
53 static int red_detach(struct ifinfo *ifinfo);
54 static int red_enable(struct ifinfo *ifinfo);
55 static int red_disable(struct ifinfo *ifinfo);
56
57 #define RED_DEVICE "/dev/altq/red"
58
59 static int red_fd = -1;
60 static int red_refcount = 0;
61
62 static struct qdisc_ops red_qdisc = {
63 ALTQT_RED,
64 "red",
65 red_attach,
66 red_detach,
67 NULL, /* clear */
68 red_enable,
69 red_disable,
70 NULL, /* add class */
71 NULL, /* modify class */
72 NULL, /* delete class */
73 NULL, /* add filter */
74 NULL /* delete filter */
75 };
76
77 /*
78 * parser interface
79 */
80 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
81
82 int
83 red_interface_parser(const char *ifname, int argc, char **argv)
84 {
85 u_int bandwidth = 100000000; /* 100Mbps */
86 u_int tbrsize = 0;
87 int weight = 0; /* 0: use default */
88 int inv_pmax = 0; /* 0: use default */
89 int th_min = 0; /* 0: use default */
90 int th_max = 0; /* 0: use default */
91 int qlimit = 60;
92 int pkttime = 0;
93 int flags = 0;
94 int packet_size = 1000;
95
96 /*
97 * process options
98 */
99 while (argc > 0) {
100 if (EQUAL(*argv, "bandwidth")) {
101 argc--; argv++;
102 if (argc > 0)
103 bandwidth = atobps(*argv);
104 } else if (EQUAL(*argv, "tbrsize")) {
105 argc--; argv++;
106 if (argc > 0)
107 tbrsize = atobytes(*argv);
108 } else if (EQUAL(*argv, "packetsize")) {
109 argc--; argv++;
110 if (argc > 0)
111 packet_size = atobytes(*argv);
112 } else if (EQUAL(*argv, "weight")) {
113 argc--; argv++;
114 if (argc > 0)
115 weight = (int)strtol(*argv, NULL, 0);
116 } else if (EQUAL(*argv, "qlimit")) {
117 argc--; argv++;
118 if (argc > 0)
119 qlimit = (int)strtol(*argv, NULL, 0);
120 } else if (EQUAL(*argv, "thmin")) {
121 argc--; argv++;
122 if (argc > 0)
123 th_min = (int)strtol(*argv, NULL, 0);
124 } else if (EQUAL(*argv, "thmax")) {
125 argc--; argv++;
126 if (argc > 0)
127 th_max = (int)strtol(*argv, NULL, 0);
128 } else if (EQUAL(*argv, "invpmax")) {
129 argc--; argv++;
130 if (argc > 0)
131 inv_pmax = (int)strtol(*argv, NULL, 0);
132 } else if (EQUAL(*argv, "red")) {
133 /* just skip */
134 } else if (EQUAL(*argv, "ecn")) {
135 flags |= REDF_ECN;
136 } else if (EQUAL(*argv, "flowvalve")) {
137 flags |= REDF_FLOWVALVE;
138 } else {
139 LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv);
140 return (0);
141 }
142 argc--; argv++;
143 }
144
145 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
146 return (0);
147
148 pkttime = packet_size * 8 * 1000 / (bandwidth / 1000);
149 if (weight != 0) {
150 /* check if weight is power of 2 */
151 int i, w;
152
153 w = weight;
154 for (i = 0; w > 1; i++)
155 w = w >> 1;
156 w = 1 << i;
157 if (weight != w) {
158 LOG(LOG_ERR, 0, "weight %d: should be power of 2",
159 weight);
160 return (0);
161 }
162 }
163
164 if (qcmd_red_add_if(ifname, bandwidth, weight, inv_pmax,
165 th_min, th_max, qlimit, pkttime, flags) != 0)
166 return (0);
167 return (1);
168 }
169
170 /*
171 * qcmd api
172 */
173 int
174 qcmd_red_add_if(const char *ifname, u_int bandwidth, int weight,
175 int inv_pmax, int th_min, int th_max, int qlimit,
176 int pkttime, int flags)
177 {
178 int error;
179
180 error = qop_red_add_if(NULL, ifname, bandwidth, weight, inv_pmax,
181 th_min, th_max, qlimit, pkttime, flags);
182 if (error != 0)
183 LOG(LOG_ERR, errno, "%s: can't add red on interface '%s'\n",
184 qoperror(error), ifname);
185 return (error);
186 }
187
188 /*
189 * qop api
190 */
191 int
192 qop_red_add_if(struct ifinfo **rp, const char *ifname,
193 u_int bandwidth, int weight, int inv_pmax, int th_min,
194 int th_max, int qlimit, int pkttime, int flags)
195 {
196 struct ifinfo *ifinfo = NULL;
197 struct red_ifinfo *red_ifinfo;
198 int error;
199
200 if ((red_ifinfo = calloc(1, sizeof(*red_ifinfo))) == NULL)
201 return (QOPERR_NOMEM);
202 red_ifinfo->weight = weight;
203 red_ifinfo->inv_pmax = inv_pmax;
204 red_ifinfo->th_min = th_min;
205 red_ifinfo->th_max = th_max;
206 red_ifinfo->qlimit = qlimit;
207 red_ifinfo->pkttime = pkttime;
208 red_ifinfo->flags = flags;
209
210 error = qop_add_if(&ifinfo, ifname, bandwidth,
211 &red_qdisc, red_ifinfo);
212 if (error != 0) {
213 free(red_ifinfo);
214 return (error);
215 }
216
217 if (rp != NULL)
218 *rp = ifinfo;
219 return (0);
220 }
221
222 /*
223 * system call interfaces for qdisc_ops
224 */
225 static int
226 red_attach(struct ifinfo *ifinfo)
227 {
228 struct red_interface iface;
229 struct red_ifinfo *red_ifinfo;
230 struct red_conf conf;
231
232 if (red_fd < 0 &&
233 (red_fd = open(RED_DEVICE, O_RDWR)) < 0 &&
234 (red_fd = open_module(RED_DEVICE, O_RDWR)) < 0) {
235 LOG(LOG_ERR, errno, "RED open\n");
236 return (QOPERR_SYSCALL);
237 }
238
239 red_refcount++;
240 memset(&iface, 0, sizeof(iface));
241 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ);
242
243 if (ioctl(red_fd, RED_IF_ATTACH, &iface) < 0)
244 return (QOPERR_SYSCALL);
245
246 /* set red parameters */
247 red_ifinfo = (struct red_ifinfo *)ifinfo->private;
248 memset(&conf, 0, sizeof(conf));
249 strncpy(conf.iface.red_ifname, ifinfo->ifname, IFNAMSIZ);
250 conf.red_weight = red_ifinfo->weight;
251 conf.red_inv_pmax = red_ifinfo->inv_pmax;
252 conf.red_thmin = red_ifinfo->th_min;
253 conf.red_thmax = red_ifinfo->th_max;
254 conf.red_limit = red_ifinfo->qlimit;
255 conf.red_flags = red_ifinfo->flags;
256 if (ioctl(red_fd, RED_CONFIG, &conf) < 0)
257 return (QOPERR_SYSCALL);
258
259 #if 1
260 LOG(LOG_INFO, 0, "red attached to %s\n", iface.red_ifname);
261 #endif
262 return (0);
263 }
264
265 static int
266 red_detach(struct ifinfo *ifinfo)
267 {
268 struct red_interface iface;
269
270 memset(&iface, 0, sizeof(iface));
271 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ);
272
273 if (ioctl(red_fd, RED_IF_DETACH, &iface) < 0)
274 return (QOPERR_SYSCALL);
275
276 if (--red_refcount == 0) {
277 close(red_fd);
278 red_fd = -1;
279 }
280 return (0);
281 }
282
283 static int
284 red_enable(struct ifinfo *ifinfo)
285 {
286 struct red_interface iface;
287
288 memset(&iface, 0, sizeof(iface));
289 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ);
290
291 if (ioctl(red_fd, RED_ENABLE, &iface) < 0)
292 return (QOPERR_SYSCALL);
293 return (0);
294 }
295
296 static int
297 red_disable(struct ifinfo *ifinfo)
298 {
299 struct red_interface iface;
300
301 memset(&iface, 0, sizeof(iface));
302 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ);
303
304 if (ioctl(red_fd, RED_DISABLE, &iface) < 0)
305 return (QOPERR_SYSCALL);
306 return (0);
307 }
308