xref: /netbsd-src/usr.sbin/altq/libaltq/qop_rio.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
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 *ifinfo);
54 static int rio_detach(struct ifinfo *ifinfo);
55 static int rio_enable(struct ifinfo *ifinfo);
56 static int rio_disable(struct ifinfo *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