xref: /netbsd/usr.sbin/altq/libaltq/qop_priq.c (revision 2dbb216c)
1 /*	$NetBSD: qop_priq.c,v 1.6 2013/10/19 17:16:37 christos Exp $	*/
2 /*	$KAME: qop_priq.c,v 1.4 2001/12/03 08:20:55 kjc Exp $	*/
3 /*
4  * Copyright (C) 2000
5  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  */
28 
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>
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stddef.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <syslog.h>
46 #include <netdb.h>
47 
48 #include <altq/altq.h>
49 #include <altq/altq_priq.h>
50 #include "altq_qop.h"
51 #include "qop_priq.h"
52 
53 static int qop_priq_enable_hook(struct ifinfo *);
54 
55 static int priq_attach(struct ifinfo *);
56 static int priq_detach(struct ifinfo *);
57 static int priq_clear(struct ifinfo *);
58 static int priq_enable(struct ifinfo *);
59 static int priq_disable(struct ifinfo *);
60 static int priq_add_class(struct classinfo *);
61 static int priq_modify_class(struct classinfo *, void *);
62 static int priq_delete_class(struct classinfo *);
63 static int priq_add_filter(struct fltrinfo *);
64 static int priq_delete_filter(struct fltrinfo *);
65 
66 #define PRIQ_DEVICE	"/dev/altq/priq"
67 
68 static int priq_fd = -1;
69 static int priq_refcount = 0;
70 
71 static struct qdisc_ops priq_qdisc = {
72 	ALTQT_PRIQ,
73 	"priq",
74 	priq_attach,
75 	priq_detach,
76 	priq_clear,
77 	priq_enable,
78 	priq_disable,
79 	priq_add_class,
80 	priq_modify_class,
81 	priq_delete_class,
82 	priq_add_filter,
83 	priq_delete_filter,
84 };
85 
86 #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
87 
88 /*
89  * parser interface
90  */
91 int
priq_interface_parser(const char * ifname,int argc,char ** argv)92 priq_interface_parser(const char *ifname, int argc, char **argv)
93 {
94 	u_int  	bandwidth = 100000000;	/* 100Mbps */
95 	u_int	tbrsize = 0;
96 	int	flags = 0;
97 
98 	/*
99 	 * process options
100 	 */
101 	while (argc > 0) {
102 		if (EQUAL(*argv, "bandwidth")) {
103 			argc--; argv++;
104 			if (argc > 0)
105 				bandwidth = atobps(*argv);
106 		} else if (EQUAL(*argv, "tbrsize")) {
107 			argc--; argv++;
108 			if (argc > 0)
109 				tbrsize = atobytes(*argv);
110 		} else if (EQUAL(*argv, "priq")) {
111 			/* just skip */
112 		} else {
113 			LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv);
114 			return (0);
115 		}
116 		argc--; argv++;
117 	}
118 
119 	if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
120 		return (0);
121 
122 	if (qcmd_priq_add_if(ifname, bandwidth, flags) != 0)
123 		return (0);
124 	return (1);
125 }
126 
127 int
priq_class_parser(const char * ifname,const char * class_name,const char * parent_name,int argc,char ** argv)128 priq_class_parser(const char *ifname, const char *class_name,
129 		  const char *parent_name, int argc, char **argv)
130 {
131 	int	pri = 0, qlimit = 50;
132 	int	flags = 0, error;
133 
134 	while (argc > 0) {
135 		if (EQUAL(*argv, "priority")) {
136 			argc--; argv++;
137 			if (argc > 0)
138 				pri = strtoul(*argv, NULL, 0);
139 		} else if (EQUAL(*argv, "qlimit")) {
140 			argc--; argv++;
141 			if (argc > 0)
142 				qlimit = strtoul(*argv, NULL, 0);
143 		} else if (EQUAL(*argv, "default")) {
144 			flags |= PRCF_DEFAULTCLASS;
145 		} else if (EQUAL(*argv, "red")) {
146 			flags |= PRCF_RED;
147 		} else if (EQUAL(*argv, "ecn")) {
148 			flags |= PRCF_ECN;
149 		} else if (EQUAL(*argv, "rio")) {
150 			flags |= PRCF_RIO;
151 		} else if (EQUAL(*argv, "cleardscp")) {
152 			flags |= PRCF_CLEARDSCP;
153 		} else {
154 			LOG(LOG_ERR, 0,
155 			    "Unknown keyword '%s' in %s, line %d",
156 			    *argv, altqconfigfile, line_no);
157 			return (0);
158 		}
159 
160 		argc--; argv++;
161 	}
162 
163 	if ((flags & PRCF_ECN) && (flags & (PRCF_RED|PRCF_RIO)) == 0)
164 		flags |= PRCF_RED;
165 
166 	error = qcmd_priq_add_class(ifname, class_name, pri, qlimit, flags);
167 
168 	if (error) {
169 		LOG(LOG_ERR, errno, "priq_class_parser: %s",
170 		    qoperror(error));
171 		return (0);
172 	}
173 	return (1);
174 }
175 
176 /*
177  * qcmd api
178  */
179 int
qcmd_priq_add_if(const char * ifname,u_int bandwidth,int flags)180 qcmd_priq_add_if(const char *ifname, u_int bandwidth, int flags)
181 {
182 	int error;
183 
184 	error = qop_priq_add_if(NULL, ifname, bandwidth, flags);
185 	if (error != 0)
186 		LOG(LOG_ERR, errno, "%s: can't add priq on interface '%s'",
187 		    qoperror(error), ifname);
188 	return (error);
189 }
190 
191 int
qcmd_priq_add_class(const char * ifname,const char * class_name,int pri,int qlimit,int flags)192 qcmd_priq_add_class(const char *ifname, const char *class_name,
193 		    int pri, int qlimit, int flags)
194 {
195 	struct ifinfo *ifinfo;
196 	int error = 0;
197 
198 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
199 		error = QOPERR_BADIF;
200 
201 	if (error == 0)
202 		error = qop_priq_add_class(NULL, class_name, ifinfo,
203 					   pri, qlimit, flags);
204 	if (error != 0)
205 		LOG(LOG_ERR, errno,
206 		    "priq: %s: can't add class '%s' on interface '%s'",
207 		    qoperror(error), class_name, ifname);
208 	return (error);
209 }
210 
211 int
qcmd_priq_modify_class(const char * ifname,const char * class_name,int pri,int qlimit,int flags)212 qcmd_priq_modify_class(const char *ifname, const char *class_name,
213 		       int pri, int qlimit, int flags)
214 {
215 	struct ifinfo *ifinfo;
216 	struct classinfo *clinfo;
217 
218 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
219 		return (QOPERR_BADIF);
220 
221 	if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL)
222 		return (QOPERR_BADCLASS);
223 
224 	return qop_priq_modify_class(clinfo, pri, qlimit, flags);
225 }
226 
227 /*
228  * qop api
229  */
230 int
qop_priq_add_if(struct ifinfo ** rp,const char * ifname,u_int bandwidth,int flags)231 qop_priq_add_if(struct ifinfo **rp, const char *ifname,
232 		u_int bandwidth, int flags)
233 {
234 	struct ifinfo *ifinfo = NULL;
235 	struct priq_ifinfo *priq_ifinfo = NULL;
236 	int error;
237 
238 	if ((priq_ifinfo = calloc(1, sizeof(*priq_ifinfo))) == NULL)
239 		return (QOPERR_NOMEM);
240 
241 	error = qop_add_if(&ifinfo, ifname, bandwidth,
242 			   &priq_qdisc, priq_ifinfo);
243 	if (error != 0)
244 		goto err_ret;
245 
246 	/* set enable hook */
247 	ifinfo->enable_hook = qop_priq_enable_hook;
248 
249 	if (rp != NULL)
250 		*rp = ifinfo;
251 	return (0);
252 
253  err_ret:
254 	if (priq_ifinfo != NULL) {
255 		free(priq_ifinfo);
256 		if (ifinfo != NULL)
257 			ifinfo->private = NULL;
258 	}
259 	return (error);
260 }
261 
262 int
qop_priq_add_class(struct classinfo ** rp,const char * class_name,struct ifinfo * ifinfo,int pri,int qlimit,int flags)263 qop_priq_add_class(struct classinfo **rp, const char *class_name,
264 		   struct ifinfo *ifinfo, int pri, int qlimit, int flags)
265 {
266 	struct classinfo *clinfo;
267 	struct priq_ifinfo *priq_ifinfo;
268 	struct priq_classinfo *priq_clinfo = NULL;
269 	int error;
270 
271 	priq_ifinfo = ifinfo->private;
272 	if ((flags & PRCF_DEFAULTCLASS) && priq_ifinfo->default_class != NULL)
273 		return (QOPERR_CLASS_INVAL);
274 
275 	if ((priq_clinfo = calloc(1, sizeof(*priq_clinfo))) == NULL) {
276 		error = QOPERR_NOMEM;
277 		goto err_ret;
278 	}
279 
280 	priq_clinfo->pri = pri;
281 	priq_clinfo->qlimit = qlimit;
282 	priq_clinfo->flags = flags;
283 
284 	if ((error = qop_add_class(&clinfo, class_name, ifinfo, NULL,
285 				   priq_clinfo)) != 0)
286 		goto err_ret;
287 
288 	if (flags & PRCF_DEFAULTCLASS)
289 		priq_ifinfo->default_class = clinfo;
290 
291 	if (rp != NULL)
292 		*rp = clinfo;
293 	return (0);
294 
295  err_ret:
296 	if (priq_clinfo != NULL) {
297 		free(priq_clinfo);
298 		clinfo->private = NULL;
299 	}
300 
301 	return (error);
302 }
303 
304 int
qop_priq_modify_class(struct classinfo * clinfo,int pri,int qlimit,int flags)305 qop_priq_modify_class(struct classinfo *clinfo,
306 		      int pri, int qlimit, int flags)
307 {
308 	struct priq_classinfo *priq_clinfo;
309 	int error;
310 
311 	priq_clinfo = clinfo->private;
312 	if (clinfo->parent == NULL)
313 		return (QOPERR_CLASS_INVAL);
314 
315 	priq_clinfo->pri = pri;
316 	priq_clinfo->qlimit = qlimit;
317 	priq_clinfo->flags = flags;
318 
319 	error = qop_modify_class(clinfo, NULL);
320 	if (error == 0)
321 		return (0);
322 	return (error);
323 }
324 
325 /*
326  * sanity check at enabling priq:
327  *  1. there must one default class for an interface
328  */
329 static int
qop_priq_enable_hook(struct ifinfo * ifinfo)330 qop_priq_enable_hook(struct ifinfo *ifinfo)
331 {
332 	struct priq_ifinfo *priq_ifinfo;
333 
334 	priq_ifinfo = ifinfo->private;
335 	if (priq_ifinfo->default_class == NULL) {
336 		LOG(LOG_ERR, 0, "priq: no default class on interface %s!",
337 		    ifinfo->ifname);
338 		return (QOPERR_CLASS);
339 	}
340 	return (0);
341 }
342 
343 /*
344  *  system call interfaces for qdisc_ops
345  */
346 static int
priq_attach(struct ifinfo * ifinfo)347 priq_attach(struct ifinfo *ifinfo)
348 {
349 	struct priq_interface iface;
350 
351 	memset(&iface, 0, sizeof(iface));
352 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
353 
354 	if (priq_fd < 0 &&
355 	    (priq_fd = open(PRIQ_DEVICE, O_RDWR)) < 0 &&
356 	    (priq_fd = open_module(PRIQ_DEVICE, O_RDWR)) < 0) {
357 		LOG(LOG_ERR, errno, "PRIQ open");
358 		return (QOPERR_SYSCALL);
359 	}
360 
361 	priq_refcount++;
362 	memset(&iface, 0, sizeof(iface));
363 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
364 	iface.arg = ifinfo->bandwidth;
365 
366 	if (ioctl(priq_fd, PRIQ_IF_ATTACH, &iface) < 0)
367 		return (QOPERR_SYSCALL);
368 	return (0);
369 }
370 
371 static int
priq_detach(struct ifinfo * ifinfo)372 priq_detach(struct ifinfo *ifinfo)
373 {
374 	struct priq_interface iface;
375 
376 	memset(&iface, 0, sizeof(iface));
377 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
378 
379 	if (ioctl(priq_fd, PRIQ_IF_DETACH, &iface) < 0)
380 		return (QOPERR_SYSCALL);
381 
382 	if (--priq_refcount == 0) {
383 		close(priq_fd);
384 		priq_fd = -1;
385 	}
386 	return (0);
387 }
388 
389 static int
priq_clear(struct ifinfo * ifinfo)390 priq_clear(struct ifinfo *ifinfo)
391 {
392 	struct priq_interface iface;
393 
394 	memset(&iface, 0, sizeof(iface));
395 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
396 
397 	if (ioctl(priq_fd, PRIQ_CLEAR, &iface) < 0)
398 		return (QOPERR_SYSCALL);
399 	return (0);
400 }
401 
402 static int
priq_enable(struct ifinfo * ifinfo)403 priq_enable(struct ifinfo *ifinfo)
404 {
405 	struct priq_interface iface;
406 
407 	memset(&iface, 0, sizeof(iface));
408 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
409 
410 	if (ioctl(priq_fd, PRIQ_ENABLE, &iface) < 0)
411 		return (QOPERR_SYSCALL);
412 	return (0);
413 }
414 
415 static int
priq_disable(struct ifinfo * ifinfo)416 priq_disable(struct ifinfo *ifinfo)
417 {
418 	struct priq_interface iface;
419 
420 	memset(&iface, 0, sizeof(iface));
421 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
422 
423 	if (ioctl(priq_fd, PRIQ_DISABLE, &iface) < 0)
424 		return (QOPERR_SYSCALL);
425 	return (0);
426 }
427 
428 static int
priq_add_class(struct classinfo * clinfo)429 priq_add_class(struct classinfo *clinfo)
430 {
431 	struct priq_add_class class_add;
432 	struct priq_classinfo *priq_clinfo;
433 
434 	priq_clinfo = clinfo->private;
435 
436 	memset(&class_add, 0, sizeof(class_add));
437 	strncpy(class_add.iface.ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
438 
439 	class_add.pri = priq_clinfo->pri;
440 	class_add.qlimit = priq_clinfo->qlimit;
441 	class_add.flags = priq_clinfo->flags;
442 	if (ioctl(priq_fd, PRIQ_ADD_CLASS, &class_add) < 0) {
443 		clinfo->handle = PRIQ_NULLCLASS_HANDLE;
444 		return (QOPERR_SYSCALL);
445 	}
446 	clinfo->handle = class_add.class_handle;
447 	return (0);
448 }
449 
450 static int
priq_modify_class(struct classinfo * clinfo,void * arg)451 priq_modify_class(struct classinfo *clinfo, void *arg)
452 {
453 	struct priq_modify_class class_mod;
454 	struct priq_classinfo *priq_clinfo;
455 
456 	priq_clinfo = clinfo->private;
457 
458 	memset(&class_mod, 0, sizeof(class_mod));
459 	strncpy(class_mod.iface.ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
460 	class_mod.class_handle = clinfo->handle;
461 
462 	class_mod.pri = priq_clinfo->pri;
463 	class_mod.qlimit = priq_clinfo->qlimit;
464 	class_mod.flags = priq_clinfo->flags;
465 
466 	if (ioctl(priq_fd, PRIQ_MOD_CLASS, &class_mod) < 0)
467 		return (QOPERR_SYSCALL);
468 	return (0);
469 }
470 
471 static int
priq_delete_class(struct classinfo * clinfo)472 priq_delete_class(struct classinfo *clinfo)
473 {
474 	struct priq_delete_class class_delete;
475 
476 	if (clinfo->handle == PRIQ_NULLCLASS_HANDLE)
477 		return (0);
478 
479 	memset(&class_delete, 0, sizeof(class_delete));
480 	strncpy(class_delete.iface.ifname, clinfo->ifinfo->ifname,
481 		IFNAMSIZ);
482 	class_delete.class_handle = clinfo->handle;
483 
484 	if (ioctl(priq_fd, PRIQ_DEL_CLASS, &class_delete) < 0)
485 		return (QOPERR_SYSCALL);
486 	return (0);
487 }
488 
489 static int
priq_add_filter(struct fltrinfo * fltrinfo)490 priq_add_filter(struct fltrinfo *fltrinfo)
491 {
492 	struct priq_add_filter fltr_add;
493 
494 	memset(&fltr_add, 0, sizeof(fltr_add));
495 	strncpy(fltr_add.iface.ifname, fltrinfo->clinfo->ifinfo->ifname,
496 		IFNAMSIZ);
497 	fltr_add.class_handle = fltrinfo->clinfo->handle;
498 	fltr_add.filter = fltrinfo->fltr;
499 
500 	if (ioctl(priq_fd, PRIQ_ADD_FILTER, &fltr_add) < 0)
501 		return (QOPERR_SYSCALL);
502 	fltrinfo->handle = fltr_add.filter_handle;
503 	return (0);
504 }
505 
506 static int
priq_delete_filter(struct fltrinfo * fltrinfo)507 priq_delete_filter(struct fltrinfo *fltrinfo)
508 {
509 	struct priq_delete_filter fltr_del;
510 
511 	memset(&fltr_del, 0, sizeof(fltr_del));
512 	strncpy(fltr_del.iface.ifname, fltrinfo->clinfo->ifinfo->ifname,
513 		IFNAMSIZ);
514 	fltr_del.filter_handle = fltrinfo->handle;
515 
516 	if (ioctl(priq_fd, PRIQ_DEL_FILTER, &fltr_del) < 0)
517 		return (QOPERR_SYSCALL);
518 	return (0);
519 }
520 
521 
522